【问题标题】:Changing Object keys & values and preserving the initial order更改对象键和值并保留初始顺序
【发布时间】:2021-12-03 11:05:09
【问题描述】:

给定下面的状态对象

{
  colour: ['red', 'blue', 'green'],
  size: ['small', 'medium', 'large'],
  position: ['bottom', 'top', 'left', 'right'],
}

我需要能够更改/更新其属性值attrValues 以及属性键attrKey

我正在使用以下逻辑来做到这一点:

setAttributes((prevState) => {
  const key = Object.keys(attributeToUpdate)[0];
  if (key !== attrKey) {
    delete prevState[key];
  }
  return { ...prevState, [attrKey]: attrValue };
});

如果我将colour 的属性键更改为color,它会起作用,但结果状态会更改为:

{
  size: ['small', 'medium', 'large'],
  position: ['bottom', 'top', 'left', 'right'],
  color: ['red', 'blue', 'green'],
}

color 属性移到最后,我想保留它的原始位置。

任何帮助或指点将不胜感激。

【问题讨论】:

  • 对象中键的位置不是固定的(或者至少不能依赖!)。如果你需要定位东西,你需要一个数组
  • @Jamiec ... 自 ES6/ES2015 以来,除了纯基于数字的键,其插入由升序键顺序处理之外,键插入优先级/顺序是否得到保证?
  • @PeterSeliger 是的,也许我的评论很轻率 - 它可能已修复,您无法通过 AFAIK 影响该排序。我的命令应该说“无法控制”而不是“不固定”
  • 为什么订单很重要是我的问题。如果您需要映射它们,只需声明一个单独的键数组并对其进行映射。看起来像xy problem
  • @Pilchard ...我也是,总是问这个问题。在 SO,我遇到了唯一可以接受的用例。它是关于比较/更新本地存储数据,人们将在其中比较 JSON 字符串化的对象,认为(a)不需要深度对象(基于)比较,(b)实现复杂,(c)不高效.然后的方法是统一每个对象的键优先级(按字母顺序和递归),然后比较它们的字符串化版本。

标签: javascript json object key insertion-order


【解决方案1】:

尽管人们应该考虑到对密钥插入顺序/优先级表达的担忧,但 OP 正在寻找的解决方案可能会接近下一个提供的代码...

function renamePropertyAndKeepKeyPrecedence(obj, [oldKey, newKey]) {
  const descriptors = Object.getOwnPropertyDescriptors(obj);
  if (descriptors.hasOwnProperty(oldKey)) {
    Object
      .entries(descriptors)
      .reduce((target, [key, descriptor]) => {

        // delete every property.
        Reflect.deleteProperty(target, key);

        if (key === oldKey) {
          // rename addressed key.
          key = newKey;
        }
        // reassign every property.
        Reflect.defineProperty(target, key, descriptor)

        return target;

      }, obj);
  }
  return obj;
}

const sample = {
  position: ['bottom', 'top', 'left', 'right'],
  colour: ['red', 'blue', 'green'],
  size: ['small', 'medium', 'large'],
};
console.log('before property renaming ...', { sample });

renamePropertyAndKeepKeyPrecedence(sample, ['colour', 'color']);
console.log('after property renaming ...', { sample });
.as-console-wrapper { min-height: 100%!important; top: 0; }

【讨论】:

    【解决方案2】:

    您无法控制 n 对象中键的顺序 - 如果顺序很重要,您应该有一个对象数组。然后,您可以重建已删除您想要的项目并替换它的状态。

    下面的演示在实践中展示了这一点:

    let prevState = [
      {key:"colour",values: ['red', 'blue', 'green']},
      {key:"size", values:['small', 'medium', 'large']},
      {key:"position",values:['bottom', 'top', 'left', 'right']}
    ]
    
    const indexToRemove = prevState.findIndex(x => x.key == "colour");
    
    prevState = [
      ...prevState.slice(0,indexToRemove),
      {key:"color", values:['red', 'blue', 'green']},
      ...prevState.slice(indexToRemove+1)
    ]
    console.log(prevState)

    所以如果我理解你的代码,更正将是

    setAttributes((prevState) => {
      const key = Object.keys(attributeToUpdate)[0];
      const indexToRemove = prevState.findIndex(x => x.key == key);
    
      return [
        ...prevState.slice(0,indexToRemove),
        {key:attrKey, values:attrValue},
        ...prevState.slice(indexToRemove+1)
      ]
    });
    

    您必须更新其余代码以使用状态数组而不是对象。

    【讨论】:

    • 我决定使用此处指出的对象数组以及建议和 cmets,谢谢
    猜你喜欢
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 2016-04-16
    • 1970-01-01
    相关资源
    最近更新 更多