javascript 如何通过属性路径更新对象的嵌套值?[duplicate]

0vvn1miw  于 2022-12-21  发布在  Java
关注(0)|答案(1)|浏览(107)
    • 此问题在此处已有答案**:

Dynamically set property of nested object(28个答案)
8天前关闭。
我有一个json对象,我需要在给定路径的对象中添加键值对。

const data = {
  "hosts": {
    "static": {
      "domain": "http://api-azure-dev.atc.com",
      "port": 80
    },
    "azure": {
      "domain": "http://api-azure-dev.atc-v8.com",
      "port": 80
    }
  },
  "paths": {
    "static": {
      "cities": {
        "hostKey": "static",
        "path": "/cf/v2/lookups/cities",
        "method": "GET"
      }
    }
  }
};

这里我需要在路径$.paths.static.getCountryCode处添加一些值,这是jsonpath符号,其中$表示根。然后返回更新后的值。

const newConsul = {
        "hostKey": "azure",
        "path": "/v8/v1/lookups/countryCode/{country}",
        "method": "get"
    };

如何创建一个函数,将给定的newConsul的值插入到数据对象中?这样最终的数据对象看起来就像:

const data = {
  "hosts": {
    "static": {
      "domain": "http://api-azure-dev.atc.com",
      "port": 80
    },
    "azure": {
      "domain": "http://api-azure-dev.atc-v8.com",
      "port": 80
    }
  },
  "paths": {
    "static": {
      "cities": {
        "hostKey": "static",
        "path": "/cf/v2/lookups/cities",
        "method": "GET"
      },
      "getCountryCode": {
         "hostKey": "azure",
         "path": "/v8/v1/lookups/countryCode/{country}",
         "method": "get"
      }
    }
  }
};
7lrncoxx

7lrncoxx1#

由于总是需要拆分基于字符串的path值,然后需要迭代得到的key数组,以便编程地访问下一个嵌套属性值,因此可以两者都做,选择基于reduce的方法,并且首先仅从get方法的实现开始(以便演示基于reduce的访问)。
initialValue将是要迭代的对象,其中,对于每个迭代步骤,可以尝试经由例如reference?.[key]安全地访问下一嵌套值,其中reference是对最初传递的对象的最近引用,而?.[key]是通过使用Optional Chaining访问下一嵌套值的故障保护尝试。下一个迭代步骤会将此访问的结果作为第一个参数再次传递给reducer函数,这也是key数组处理完毕后reduce方法返回的值。
一个set方法将基于以前实现的get。在这里,我们不仅需要像以前一样访问下一个嵌套属性值,而且还需要在它不存在的情况下创建它。在后一种情况下,我们必须弄清楚是分配额外传递的data有效载荷还是分配一个空对象。

function get(path = '', obj = {}) {
  return String(path)
    // get rid of the optional/not needed leading characters ...  '$.'
    .replace(/^\$\./, '')
    // split the path name into an array/list of keys.
    .split('.')
    // programmatically access the next nested property value.
    .reduce((reference, key) =>
      reference?.[key], Object(obj)
    );
}
function set(path = '', obj = {}, data) {
  return String(path)
    .replace(/^\$\./, '')
    .split('.')
    // programmatically access or create the next nested property value
    // until the target key is reached and the passed data gets assigned.
    .reduce((reference, key, idx, listOfKeys) => {

      const value = (idx >= listOfKeys.length - 1)
        ? (structuredClone?.(data) ?? data)
        : {};

      return reference.hasOwnProperty(key)
        ? reference[key]
        : Object.assign(reference, { [ key ]: value })[key];

    }, Object(obj));
}

const data = {
  hosts: {
    static: {
      domain: 'http://api-azure-dev.atc.com',
      port: 80,
    },
    azure: {
      domain: 'http://api-azure-dev.atc-v8.com',
      port: 80,
    },
  },
  paths: {
    static: {
      cities: {
        hostKey: 'static',
        path: '/cf/v2/lookups/cities',
        method: 'GET',
      },
    },
  },
};
console.log({ data });

console.log(
  "get('hosts.static', data) ...",
  get('hosts.static', data),
);
console.log(
  "get('$.hosts.static.domain', data) ...",
  get('$.hosts.static.domain', data),
);
console.log(
  "get('$.hosts.static.foo', data) ...",
  get('$.hosts.static.foo', data),
);

console.log(`
set('$.paths.static.getCountryCode', data, {
 hostKey: 'azure',
 path: '/v8/v1/lookups/countryCode/{country}',
 method: 'get'
}) ...`,
  set('$.paths.static.getCountryCode', data, {
   hostKey: 'azure',
   path: '/v8/v1/lookups/countryCode/{country}',
   method: 'get'
  })
);
console.log({ data });
.as-console-wrapper { min-height: 100%!important; top: 0; }

相关问题