浑元功法 ---- 浅拷贝与深拷贝

156 阅读4分钟

浅拷贝和深拷贝

浅拷贝 vs 深拷贝

  • 浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝,如果属性是基本类型,拷贝该基本类型的值,如果属性是引用类型,拷贝该引用类型的内存地址。如果一个对象改变了这个地址, 就会影响到另一个对象。
  • 深拷贝:将一个对象从内存中完整拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。

赋值

// 对象赋值
let obj1 = {
    name : 'A',
    arr : [1,[2,3],4],
};
let obj2 = obj1;
obj2.name = "B";
obj2.arr[1] = [5,6,7];
console.log('obj1',obj1); // obj1 {name: 'B', arr: [1,[5,6,7],4]}
console.log('obj2',obj2); // obj2 {name: 'B', arr: [1,[5,6,7],4]}

浅拷贝

// 浅拷贝
let obj1 = {
    name : 'A',
    arr : [1,[2,3],4],
};
let obj3 = shallowClone(obj1);
obj3.name = "B";
obj3.arr[1] = [5,6,7]; // 新旧对象还是共享同一块内存

// 这是个浅拷贝的方法
function shallowClone(source) {
    var target = {};
    for (var i in source) {
        if (source.hasOwnProperty(i)) {
            target[i] = source[i];
        }
    }
    return target;
}
console.log('obj1',obj1); // obj1 {name: 'A', arr: [1,[5,6,7],4]}
console.log('obj3',obj3); // obj3 {name: 'B', arr: [1,[5,6,7],4]}

深拷贝

// 深拷贝
let obj1 = {
    name'A',
    arr: [1,[2,3],4],
};
let obj4 = deepClone(obj1);
obj4.name = "B";
obj4.arr[1] = [5,6,7]; // 新对象跟原对象不共享内存

// 这是个深拷贝的方法
function deepClone(obj) {
    if (obj === nullreturn obj; 
    if (obj instanceof Datereturn new Date(obj);
    if (obj instanceof RegExpreturn new RegExp(obj);
    if (typeof obj !== "object"return obj;
    let cloneObj = new obj.constructor();
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        // 实现一个递归拷贝
        cloneObj[key] = deepClone(obj[key]);
      }
    }
    return cloneObj;
}
console.log('obj1',obj1); // obj1 {name: 'A', arr:[1,[2,3], 4]}
console.log('obj4',obj4); // obj4 {name: 'B', arr:[1,[5,6,7], 4]}

浅拷贝的实现方式

  1. Object.assign():把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
let obj1 = { person: {name: "Messi", age: 33}, club: 'Barcelona' };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "Suarez";
obj2.club = 'Atlético Madrid';
console.log(obj1); // { person: { name: 'Suarez', age: 33 }, club: 'Barcelona' }
  1. 函数库lodash的_.clone方法
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f); // true
  1. 展开运算符...
let obj1 = { name: 'Messi', address:{ x: 100, y: 100 } } 
let obj2 = {... obj1}
obj1.address.x = 200;
obj1.name = 'Suarez';
console.log('obj2', obj2); // obj2 { name: 'Messi', address: { x: 200, y: 100 } }
  1. Array.prototype.concat()
let arr = [ 13, { username: 'Messi' } ];
let arr2 = arr.concat();
arr2[2].username = 'Suarez';
console.log(arr); // [ 1, 3, { username: 'Suarez' } ]
  1. Array.prototype.slice()
let arr = [13, { username: 'Messi' } ];
let arr3 = arr.slice();
arr3[2].username = 'Suarez'
console.log(arr); // [ 1, 3, { username: 'Suarez' } ]

深拷贝的实现方式

  1. JSON.parse(JSON.stringify()): 利用JSON.stringify将对象转成JSON字符串, 再用JSON.parse把字符串解析成对象, 一去一来, 新的对象产生了, 而且对象会开辟新的栈, 实现深拷贝(不能处理函数和正则)
let arr1 = [13, { username: 'Messi' }, function(){} ];
let arr2 = JSON.parse(JSON.stringify(arr1));
arr2[2].username = 'Suarez';
  1. 函数库lodash的_.cloneDeep方法
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f); // false
  1. jQuery.extend()方法
$.extend(deepCopy, target, object1, [objectN]) // 第一个参数为true, 就是深拷贝