数组深浅拷贝问题引发的思考

时间:2021-1-8 作者:admin

今天同事问我一个问题:”为什么我深拷贝数组没用啊,我改变其中的值后,原来的数组的值也改变了…”。作为一个努力学习的前端小白,我当然不能错过这个坑了,最后终于算是解决了,由此而引出这篇文章来记录这个坑。

引子

请看以下代码:

let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2[0] = 4;
console.log(arr1);

老司机一看就知道控制台将打印[4, 2, 3],老司机当然也知道如何避免这个坑。用ES6来写的话很简单就避免了这个坑。

let arr2 = Array.from(arr1);

ES6就是这么简单。

抛出问题

我同事开发时写的代码大致如下:

let arr1 = [{ name: 'js' }];
let arr2 = Array.from(arr1);

// 接下来他就要针对arr2进行操作了
arr2[0].name = 'css';
console.log(arr1);

我擦,上面的代码打印出的是{ name: "css" }Array.from不管用了?我的同事满脸黑人问号。

Array.from

根据MDN,Array.from主要用于从一个类似数组或可迭代对象中创建一个新的数组实例。MDN上Array.from的polyfill中有一段代码:

while (k < len) {
  kValue = items[k];
  if (mapFn) {
    A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
  } else {
    A[k] = kValue;
  }
  k += 1;
}

所以我推测Array.from采用的是浅拷贝,毕竟它的作用主要是用于转换类数组和可迭代对象。

Object.assign

let arr1 = [{ name: 'js' }];
let arr2 = [];

arr1.map(obj => arr2.push(Object.assign({}, obj)));

arr2[0].name = 'css';
console.log(arr1);

使用Object.assign轻松解决了同事的问题。那么使用Object.assign是不是就意味着万事大吉了呢?很可惜并不是,请看以下代码:

let arr1 = [{ status: 200, res: { info: 'succes' } }];
let arr2 = [];

arr1.map(obj => arr2.push(Object.assign({}, obj)));

arr2[0].res.info = 'failed';
console.log(arr1);

控制台打印的是info: failed。没错,Object.assign是浅拷贝。哈哈哈哈…

递归浅拷贝

有的同学,可能就说了,既然浅拷贝不行,那就递归浅拷贝实现深拷贝喽。说干就干:

function clone(obj) {
  if (typeof obj !== 'object') {
    return obj;
  }

  let toStr = Object.prototype.toString;
  let newObj = {};
  let isArray = toStr.call(obj) === '[object Array]';

  if (isArray) {
    newObj = [];
    Object.keys(obj).map(key => newObj.push(clone(obj[key])));
  } else {
    Object.keys(obj).map(key => newObj[key] = clone(obj[key]));
  }

  return newObj;
}

测试以下:

let arr1 = [{ status: 200, res: { info: 'succes' } }];
let arr2 = clone(arr1);

arr2[0].res.info = 'failed';
console.log(arr1);

没问题,通过。再测试以下:

let arr1 = [
  [
    { status: 200, res: { info: 'succes' } },
    { status: 301, res: { info: 'test' } }
  ]
];
let arr2 = clone(arr1);

arr2[0][0].res.info = 'failed';
console.log(arr1);

没问题,通过。

结束语

数组深浅拷贝的话题其实一直都存在,网上也有很多文章提出了很多解决方案,但大多本质都是递归,我写这篇文章也算是做出了自己的一些思考,并记录了一个坑点。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。