JavaScript浅拷贝和深拷贝

186 阅读1分钟

JavaScript数据类型

原始数据类型:String、Number、Boolean、Null、Undefined、Symbol
引用数据类型:Object、Array、Function

JavaScript赋值方式

值传递:原始数据类型在值传递的时候是通过值传递的
引用传递:引用数据类型是通过引用传递,而不是值传递。也就是说,变量赋值只会将地址传递过去

浅拷贝

对于简单对象,浅拷贝是拷贝了对象的引用,当原对象发生变化的时候,拷贝对象也跟着变化。

var obj = {a:1,b:2};
var obj2 = obj;
obj2.a = 10;
console.log(obj.a);//跟着被改变,输出10

对于复杂对象,浅拷贝是拷贝了原对象的实例,当复杂对象的属性是引用时,拷贝的是其引用;

var obj = {a:1,b:2,c:{d:'小明'}};
var target = {};
Object.assign(target,obj);
target.a = 10;
target.c.d = '小红';
console.log(obj.a,obj.c.d);//输出1,小红

Array.prototype.slice()实现了对数组的浅拷贝
JQuery中的$.extend({}, obj)完成对对象的浅拷贝
Object.assign、Object.create、ES6的解构实现了对复杂对象的浅拷贝,简单对象的深拷贝,复杂对象的浅拷贝只对第一层简单属性进行深拷贝,其他层都是浅拷贝;
复制操作实现了对简单对象的浅拷贝;

自定义浅拷贝方法

function shallowClone(source){
    if(!source || typeof source !== 'object'){
        throw new Error('error arguments')
    }
    var targetObj = source.constructor === Object ? {}:[];
    for(var key in source){
        if(source.hasOwnProperty(key)){
            targetObj[key] = source[key];
        }
    }
    return targetObj;
}

var obj1 = {a:1,b:2,c:{d:6}};
var obj2 = shallowClone(obj1);
obj2.a = 10;
obj2.c.d = 10;
console.log(obj1);//{ a: 1, b: 2, c: { d: 10 } }
console.log(obj2);//{ a: 10, b: 2, c: { d: 10 } }

深拷贝

深拷贝也就是拷贝出一个新的实例,新的实例和之前的实例互不影响;
深拷贝的几种实现方式:$.extend(true, {}, ...)、JSON.stringify将能json化的对象json化,像undefined和function不能json化,再调用JSON.parse相当于深拷贝;
自定义深拷贝方式

function deepClone(source) {
    if (!source || typeof source !== 'object') {
        throw new Error('error arguments')
    }
    var targetObj = source.constructor === Object ? {} : [];
    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            if (typeof source[key] === 'object') {
                targetObj[key] = deepClone(source[key]);
            } else {
                targetObj[key] = source[key];
            }
        }
    }
    return targetObj;
}

var obj1 = {a:1,b:2,c:{d:6}};
var obj2 = deepClone(obj1);
obj2.a = 10;
obj2.c.d = 10;
console.log(obj1);//{ a: 1, b: 2, c: { d: 6 } },被克隆的对象改变以后,原对象没有任何属性有改变
console.log(obj2);//{ a: 10, b: 2, c: { d: 10 } }