JS 浅拷贝和深拷贝

浅拷贝

新的对象复制已有对象中非对象属性的和对象属性的引用

数组的 slice、concat 、展开运算符… 返回的是浅拷贝的对象。

var a = [ 1, 3, 5, { x: 1 } ];
var b = Array.prototype.slice.call(a);
b[0] = 2;
console.log(a); // [ 1, 3, 5, { x: 1 } ];
console.log(b); // [ 2, 3, 5, { x: 1 } ];
let arr = [1, 2, 3];
let newArr = [...arr]; //同arr.slice()是一样的效果

数组里面嵌套了对象或者数组的话,就会出现不一样的结果。

var a = [ 1, 3, 5, { x: 1 } ];
var b = Array.prototype.slice.call(a);
b[3].x = 2;
console.log(a); // [ 1, 3, 5, { x: 2 } ];
console.log(b); // [ 1, 3, 5, { x: 2 } ];

对象方法Object.assign属于浅拷贝

var a = {x:1, y: {x:2}};
var b = Object.assign({}, a);
b.x = 2;
b.y.x = 3;
console.log(a); //{x:1, y:{x:3}}
console.log(b); //{x:2, y:{x:3}}

如果数组元素是基本类型,就会拷贝一份,互不影响
但是如果是对象数组这样的引用类型的时候拷贝的就是其引用,这样无论在新旧数组进行了修改两者都会发生改变

浅拷贝实现

var arr = [1,{b:function(){ console.log(2) }}, function(){ console.log(1) },[5,6]]
var shallowCopy = function(obj) {
    // 只拷贝对象
    if (typeof obj !== 'object') return;
    // 根据obj的类型判断是新建一个数组还是对象
    var newObj = obj instanceof Array ? [] : {};
    // 遍历obj,并且判断是obj的属性才拷贝
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}
let new_arr = shallowCopy(arr)
new_arr[1].b() // 2 证明浅拷贝成功 包括函数
new_arr[0] // 1
arr[3][1]=111
console.log(new_arr[3][1]) //1111

深拷贝

遍历一个对象中所有的属性的值及对象属性中的属性值,不论是嵌套了几层,要完成所有对象属性的递归后,赋值给一个新的对象。

var a = { x: 1, y: { x: 1 } };
function copy(data) {
var b={};
  if (typeof data === 'number') {
    return data
  }
  for (var i in data) {
        if (data.hasOwnProperty(i)) {
      b[i] = copy(data[i]);
    }
  }
  return b;
}

也可以使用快捷的深拷贝方式,完成对象复制,但是这种方式要求所要复制的对象的属性值是非函数。

 var arr = [{name:'xiao'}, [1]]
 var new_arr = JSON.parse(JSON.stringify(arr));
 new_arr[0].name = 'big';
 arr[1][0] = 2;
 console.log(arr) //[{name:'xiao'}, [2]]
 console.log(new_arr)//[{name:'big'}, [1]]

深拷贝实现

 var arr = [1,{b:function(){ console.log(2) }}, function(){ console.log(1) },[5,6]]
 var deepCopy = function(obj) {
     // 只拷贝对象
     if (typeof obj !== 'object') return;
     // 根据obj的类型判断是新建一个数组还是对象
     var newObj = obj instanceof Array ? [] : {};
     // 遍历obj,并且判断是obj的属性才拷贝
     for (var key in obj) {
         if (obj.hasOwnProperty(key)) {
             newObj[key] = typeof obj[key] !== 'object'? obj[key] : deepCopy(obj[key]);
         }
     }
     return newObj;
 }
 let new_arr = deepCopy(arr)
 arr[3][1]=111
 console.log(new_arr[3][1]) //6  证明深拷贝成功

直接赋值

let arr = [1, 2, 3];
let newArr = arr;
newArr[0] = 100;
console.log(arr);//[100, 2, 3]

这是直接赋值的情况,不涉及任何拷贝。当改变newArr的时候,由于是同一个引用,arr指向的值也跟着改变。

参考:

看看你知道的“浅拷贝”是对的吗

js 深浅拷贝

day035: JS中浅拷贝的手段有哪些?