JS基础心法-深浅拷贝

一、复制

浅拷贝

浅拷贝的意思就是只复制引用,而未复制真正的值。

// 数组
const originArr = [1, 2, 3]
const cloneArr = originArr
cloneArr[0] = 'a'
console.log(cloneArr) // [a, 2, 3]
// 原先的数组也改变了
console.log(originArr)// [a, 2, 3,]
// 指向的内存是一样的,所以返回true
console.log(cloneArr === originArr) // true

// 对象
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = originObj;
cloneObj.a = {aa:'aa'};
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(cloneObj === originObj) // true

上面的代码是最简单的利用 = 赋值操作符实现了一个浅拷贝,可以很清楚的看到,随着 cloneArray 和 cloneObj 改变,originArray 和 originObj 也随着发生了变化。

深拷贝

深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了。
只要进行了深拷贝,它们老死不相往来,谁也不会影响谁。

目前实现深拷贝的方法不多,主要是两种方法:

1.JSON.stringify/parse的方法

利用 JSON 对象中的 parse 和 stringify

适用的情况,代码示例如下:

const originArr = [1, 2, 3]
const cloneArr = JSON.parse(JSON.stringify(originArr));
cloneArr[0] = 'a'
console.log(cloneArr) // [a, 2, 3]
// 原先的数组没有改变
console.log(originArr)// [1, 2, 3,]
// 指向的内存改变了,所以返回false
console.log(cloneArr === originArr) // false

不适用的情况,代码示例如下:

// 数组
const originArr = [1, 2, undefined]
const cloneArr = JSON.parse(JSON.stringify(originArr));
cloneArr[0] = 'a'

console.log(originArr)// [1, 2, undefined]
// 复制的数组属性丢失,为null
console.log(cloneArr) // [a, 2, null]

// 对象
const originObj = {
  name:'axuebin',
  sayHello:function(){
    console.log('Hello World');
  }
}

console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = JSON.parse(JSON.stringify(originObj));
// 复制的对象属性丢失
console.log(cloneObj); // {name: "axuebin"}

以上代码显示,如果属性里面有undefined、function、symbol就不适用了

MDN给出的原因解释:

undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时

2.递归的方法

递归的思想就很简单了,就是对每一层的数据都实现一次 创建对象->对象赋值 的操作,简单粗暴上代码:

function deepClone(source){
  const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in source){ // 遍历目标
    if(source.hasOwnProperty(keys)){
      if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = source[keys].constructor === Array ? [] : {};
        targetObj[keys] = deepClone(source[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = source[keys];
      }
    } 
  }
  return targetObj;
}

// ES6深度复制的递归方法
const deepClone = obj => {
  let clone = Object.assign({}, obj);
  Object.keys(clone).forEach(
    key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
  );
  return clone;
};

一般的:

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = deepClone(originObj);
console.log(cloneObj === originObj); // false

cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

带有函数的:

const originObj = {
  name:'axuebin',
  sayHello:function(){
    console.log('Hello World');
  }
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = deepClone(originObj);
console.log(cloneObj); // {name: "axuebin", sayHello: ƒ}

也可以。搞定。

是不是以为这样就完了?? 当然不是。请看下篇深浅拷贝拓展

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容