JavaScript 【数组】转【对象】进行某些操作后转回【数组】后,得到的数组顺序和最开始的发生变化怎么解决

新手上路,请多包涵

比如初始数组:

const arr1 = [
    {id: 1, name: 'jack'},
    {id: 3, name: 'rose'},
    {id: 2, name: 'tom'}
]

数组对象相互转化方法:

export function arrToMap(arr: any[], key: string) {
  return arr.reduce((map, item) => {
    map[item[key]] = item
    return map
  }, {})
}

export function mapToArr(map: object) {
  return Object.values(map)
}

使用:

const arrMap = arrToMap(arr1, 'id')

// 得到arrMap:
{
  "1": {
    "id": 1,
    "name": "jack"
  },
  "2": {
    "id": 2,
    "name": "tom"
  },
  "3": {
    "id": 3,
    "name": "rose"
  }
}

/*
    在得到对象后由于对象的查询是O(1)所以更快,对其进行操作后转化为数组
*/

const arr2 = mapToArr(arrMap)

// 得到arr2,顺序已经变化
[
  {
    "id": 1,
    "name": "jack"
  },
  {
    "id": 2,
    "name": "tom"
  },
  {
    "id": 3,
    "name": "rose"
  }
]
阅读 4.3k
5 个回答

可以用MapMap的顺序是根据插入顺序

image.png

对象的查找时间复杂度小

代价就是失去了数组原有的顺序信息
当然你也可以把这部分信息加到对象里,每个对象都有唯一的 index 用作顺序标记

MDN文档中关于Object.values有下面几个例子:

const obj = { foo: 'bar', baz: 42 };
console.log(Object.values(obj)); // ['bar', 42]

// Array-like object
const arrayLikeObj1 = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(arrayLikeObj1 )); // ['a', 'b', 'c']

// Array-like object with random key ordering
// When using numeric keys, the values are returned in the keys' numerical order
const arrayLikeObj2 = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.values(arrayLikeObj2 )); // ['b', 'c', 'a']

// getFoo is property which isn't enumerable
const my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = 'bar';
console.log(Object.values(my_obj)); // ['bar']

// non-object argument will be coerced to an object
console.log(Object.values('foo')); // ['f', 'o', 'o']

对于类数组对象,Object.values按数字key的升序排列输出key,进而输出value。但是规范中没有明确规定这种行为,还是依赖于具体的实现。
对于类数组对象,不推荐使用Object.values/key等方法来枚举,使用for循环遍历为宜

JS执行本身是很快的,是多大的数组啊,都需要这样优化性能了。

对象的key是“有序的”:

  1. 整型字符串Key是按照升序排列的;
  2. 其他key(非整型字符串,Symbol)都是按照插入顺序排序的。
// 调整下arrToMap逻辑
function arrToMap(arr, key) {
  return arr.reduce((map, item) => {
    // map的key加个前缀"_",这样就不是整型字符串key了,key的顺序和插入顺序保持一致了
    map['_' + item[key]] = item
    return map
  }, {})
}

// Validation
const arr2 = mapToArr(arrMap);

我有个疑问啊,对象不都是引用吗?

那么如果你没有做深拷贝之类的,其实源数组对象就是你要的结果

image.png

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