如何替换JavaScript对象数组中的键和值,同时保持顺序,求大佬指导?

原数据

tableData = [
  {
    A: '12A',
    B: '12B'
  },
  {
    A: '13A',
    B: '13B'
  }
]

D替换key和value中的A之后,顺序变了

HTML渲染

<el-table ref="tableRef" :data="tableData" size="mini" style="width: auto" @cell-mouse-enter="handleCellEnter"
  @cell-mouse-leave="handleCellLeave" @cell-click="cellClick" @header-click="headerClick"
  :header-cell-style="{ 'text-align': 'center', 'font-size': '16px', 'cursor': 'pointer' }"
  :cell-style="{ 'text-align': 'center' }">
  <el-table-column v-for="(item, index) in titleData" :key="index" :prop="keysData[index]" :label="keysData[index]">
    <div slot-scope="scope">
      <div class="seat" v-if="scope.row[keysData[index]] != null">
        <div class="yiru">{{ scope.row[keysData[index]] }}</div>
        <div class="yichu">
          <el-button type="primary">禁用</el-button>
        </div>
      </div>
      <div class="noSeat" v-else>
        <div class="yiru">{{ scope.row[keysData[index]] }}</div>
        <div class="yichu">
          <el-button type="primary">启用</el-button>
        </div>
      </div>
    </div>
  </el-table-column>
</el-table>



替换方法

this.tableData.forEach(item => {
  for (let k in item) {
    if (k == column.property && item[k] != null) {
      item[k] = item[k].replace(k, value)
      if (item.hasOwnProperty(column.property)) {
        item[value] = item[k]
        delete item[k]
      }
    }
  }
})

这个是座位图,每一个key是每一列的编号,编号修改了,那一列的座位号中的字母也要跟着变,现在头疼的是改完后数据顺序变了,编码和座位号对不上,所以我希望得到结果是替换完之后,数据顺序保持不变。或者大家有别的好方法好思路可以指导一下

 tableData = [
  {
    D: '12D',
    B: '12B'
  },
  {
    D: '13D',
    B: '13B'
  }
]
阅读 2.9k
6 个回答

Javascript 中对象的键的顺序遵循数字键的升序和非数字键的插入顺序。也就是说,JS 会把看起来像数字的键提前并按升序排序,剩下的按插入顺序排序,如:

const obj = { k1: 'v1', k2: 'v2', '1': '1', '0': '0' }
// 0 1 k1 k2

所以只要键不是数字就可以

function replaceObjKeyWithOrder<T extends object>(
  obj: T,
  kOld: keyof T & string,
  kNew: string,
) {
  const entries = Object.entries(obj),
    entry = entries.find(([k]) => k === kOld)
  entry && (entry[0] = kNew)
  return Object.fromEntries(entries)
}

const tableData = [
    {
      A: "12A",
      B: "12B",
    },
    {
      A: "13A",
      B: "13B",
    },
  ],
  newTableData = tableData.map((v) => replaceObjKeyWithOrder(v, "A", "D"))

console.log("before:", tableData)
console.log("after:", newTableData)
before: [ { A: "12A", B: "12B" }, { A: "13A", B: "13B" } ]
after: [ { D: "12A", B: "12B" }, { D: "13A", B: "13B" } ]

key的排序不是按照我们书写的方式,它是有一个规定的:

1. 可以作为数组索引的 key 按照升序排列,例如 1、2、3。
2. 是字符串不是 symbol 的 key,按照创建顺序排列。
3. symbol 类的 key 按照创建顺序排列。

参考链接:ECMA标准定义

调整对象属性的顺序并没有意义,之前我正好写过一篇笔记,你可以阅读一下 👉 Js对象 调整属性排序是否有意义

正如楼上的回答所说,对象的排序是有一个规则的,但是这个排序规则的顺序并不一定是固定的。
所以你改变 key 的“顺序”,以及利用这个“顺序”执行一些逻辑,都是不稳定的

所以最好是用数组的形式来处理,比如说:

tableData = [
  [{key:'A', value:'12A'}, {key:'B', value:'12B'}],
  [{key:'A', value:'13A'}, {key:'B', value:'13B'}],
]

如果你一定就要用 key-value 的形式,并且就是要保持顺序。可以考虑用 Map 结构 来实现。

const replaceKeyAndValue = (data, columnName, replacement) => {
    const newData = [];
    data.forEach(item => {
        const entries = []
        item.forEach((value,key) => {
            if(key === columnName) {
                entries.push([replacement,value])
            }else {
                entries.push([key,value])
            }
        });       
        newData.push(new Map(entries))
    });
    return newData
};

const tableData = [
  new Map().set('A', '12A').set('B', '12B'),
  new Map().set('A', '13A').set('B', '13B')
];

const newData = replaceKeyAndValue(tableData, 'A', 'D');

image.png

demo地址

为什么顺序变一了……看下图:

snipaste_2024-02-02_23-55-41.png

一般来说,如果想要保持顺序,最好用键值对数组而不是用对象。如果实在想用对象,也可以先转换成数组,处理完之后重新组成对象,示例:

tableData = tableData.map(it => {
    const entries = Object.entries(it)
        .map(([key, value]) => {
            if (key === "A") return ["D", value.replace("A", "D")];
            else return [key, value];
        });
    return Object.fromEntries(entries);
});

snipaste_2024-02-03_00-01-16.png

老实说,我不太懂对象里面的顺序有什么必要,其次,这个顺序应该只是浏览器展示的一个优化...

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题