JavaScript系列 — 深拷贝和浅拷贝

什么是深拷贝和浅拷贝?

深拷贝和浅拷贝是针对于 引用类型 (Array、Object)说的:

浅拷贝

浅拷贝就是指两个对象指向同一个内存地址,其中一个改变会影响另一个

就好比一栋大厦A,有别称B,所以大厦A和大厦B其实是指同一栋大厦,因为它们的地址是一模一样的。假设这栋大厦改建了,那肯定大厦A、大厦B都会改变呐

深拷贝

深拷贝就是指复制后的新对象重新指向一个新的内存地址,两个对象改变互不影响

就好比在大厦A之外再建一栋一模一样的大厦B,两栋大厦是不同地址,当然大厦A改建,大厦B就不会变化的啦

Object 浅拷贝的常用方法

1. 简单的赋值操作

var arr1 = [1,2,3];
var arr2 = arr1;
arr1[0] = 5;
console.log(arr1);    //  [5, 2, 3]
console.log(arr2);    //  [5, 2, 3]
console.log(arr1 === arr2);  //  true
复制代码

2. Object.assign( { } , obj ) (第一层深拷贝,第二层是对象/数组则是浅拷贝)

这里的 第二层 是指 object 里面的 object,当 obj2 拷贝 obj1 里面的 obj 时,会是浅拷贝

var obj1 = { a: {a: "hello"}, b: 33 };
var obj2 = Object.assign({}, obj1);
obj2.a.a = "hello world";
console.log(obj1);    //  { a: {a: "hello world"}, b: 33 };
console.log(obj2);    //  { a: {a: "hello world"}, b: 33 };
console.log(obj1 === obj2);  //  false ,第一层是深拷贝
console.log(obj1.a === obj2.a);  //  true ,第二层如果还是对象则是浅拷贝
复制代码

3. 遍历原对象拷贝的方法(第一层深拷贝,第二层是对象/数组则是浅拷贝)

var obj1 = { a: {a: "hello"}, b: 20};
var obj2 = {};
var arr = Object.entries(obj1)
for(let i=0;i<arr.length;i++){
    Object.defineProperty(obj2,arr[i][0],{
        configurable: true,
        enumerable: true,
        writable: true,
        // 以上三个的默认值均为 false,所以得设置为 true
        value: arr[i][1]
    })
}
obj2.b = 100;
console.log(obj1);    // { a: 10, b: 20}
console.log(obj2);    //  { a: 10, b: 100};
console.log(obj1 === obj2);    //  false
console.log(obj1.a === obj2.a);    // true
复制代码

大多数的实际情况我们都是考虑使用深拷贝的,只是我们要注意如果我们在无意间使用了浅拷贝,就会有篡改其他对象/数组的事件发生。当然有时候我们也还是会用浅拷贝的,比如说公有的对象等等

Object 深拷贝的常用方法

1. obj2 = JSON.parse(JSON.stringify(obj1))

var obj1 = { a: {a: "hello"}, b: 33 };
var obj2 = JSON.parse(JSON.stringify(obj));
obj2.b = "hello world";
console.log(obj1);    //  { a: "hello", b: 33 };
console.log(obj2);    //  { a: "hello world", b: 33};
console.log(obj1===obj2);  //  false
复制代码

缺点:

  • 无法拷贝函数类型的属性
  • 会会抛弃对象的 constructor属性,也就是说无法追踪原来的构造函数是哪个

2. 自定义方法

由于对象里面有对象,所以不能只是停留在表层复制,得有深入,这个深入就是递归

function deepClone(obj1){
  if(typeof obj1 !== "object") return; // (因为有递归)进来先判断是否为引用类型
  let obj2 = obj1 instanceof Array ? [] : {}; // 判断是数组还是对象
  for(let key in obj1){
     if(obj.hasOwnProperty(key)){ // 拷贝原对象 obj 的自身属性就好
        obj2[key] = typeof obj1[key] === "object" ? deepClone(obj1[key]) : obj1[key];
    }      
  }  
  return obj2;  
}
复制代码

测试:

let obj = {a: 11, b: function(){}, c: {d: 22}};
deepClone(obj);  // {a: 11, b: f(), c: {d: 22}};
复制代码

Array 浅拷贝

1. 直接赋值

var arr1 = [1,2,3]
var arr2 = arr1
arr2[0] = 4
console.log(arr1) // [4,2,3]
console.log(arr2) // [4,2,3]
console.log(arr1 === arr2) // true
复制代码

2. arr2 = arr1.slice(0)(第一层深拷贝,第二层是对象/数组则是浅拷贝)

var arr1 = [1,2,{name: "Jack"}]
var arr2 = arr1.slice
arr2[0] = 4
console.log(arr1) // [1,2,{name: "Jack"}]
console.log(arr2) // [4,2,{name: "Jack"}]
console.log(arr1 === arr2) // false
console.log(arr1[2] === arr2[2]) // true
复制代码

3. arr2 = [].concat(arr1)(第一层深拷贝,第二层是对象/数组则是浅拷贝)

var arr1 = [1,2,[4,5,6]]
var arr2 = [].concat(arr1)
arr2[0] = 4
console.log(arr1) // [1,2,[4,5,6]]
console.log(arr2) // [4,2,[4,5,6]]
console.log(arr1 === arr2) // false
console.log(arr1[2] === arr2[2]) // true
复制代码

Array 深拷贝

1. arrr2 = JSON.parse(JSON.stringify(arr1))

var arr1 = [1,2,[4,5,6]]
var arr2 = JSON.parse(JSON.stringify(arr1))
console.log(arr1 === arr2) // false
console.log(arr1[2] === arr2[2]) // false
复制代码

2. 自定义方法

采用上面自定义方法实现对象深拷贝的例子(数组可以看成对象)

参考文章

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享