JS对象的克隆

214 阅读2分钟

在JS中一切都是对象,分为原始类型和合成类型:

原始类型:Undefined、Null、Boolean、String、Number,按值传递

合成类型:array、object和function,按内存中的地址传递。

浅克隆:基本类型按值传递,对象是引用传递;

深克隆:所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。

Object.assign, JSON.stringifyJSON.parse 方法去克隆一个对象,这个可以明确告诉大家这些都是些不靠谱的浅度克隆。

一:Object.assign()

Object.assign方法用于对象的合并,将源对象( source )的所有可枚举属性,复制到目标对象( target )。

Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

var x = {
  a: 1,
  b: { f: { g: 1 } },
  c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f);     // true

二:JSON对象的parse和stringify

//例1
var source = { name:"source", child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
target.name = "target";  //改变target的name属性
console.log(source.name); //source 
console.log(target.name); //target
target.child.name = "target child"; //改变target的child 
console.log(source.child.name); //child 
console.log(target.child.name); //target child
//例2
var source = { name:function(){console.log(1);}, child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
//例3
var source = { name:function(){console.log(1);}, child:new RegExp("e") }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
console.log(target.child); //Object {}

这种方法使用较为简单,可以满足基本的深拷贝需求,而且能够处理JSON格式能表示的所有数据类型,但是对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值)。还有一点不好的地方是它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。同时如果对象中存在循环引用的情况也无法正确处理。


浅克隆

function shallowClone(obj){
    let tmp = {};
    for(let i in obj){
        tmp[i] = obj[i];
    }
    return tmp;
}

深克隆

function deepClone(obj) {
    if(typeof obj !== 'object' && typeof obj !== 'function'){
        return obj;
    }
    var tmp = Array.isArray(obj) ? []:{};
    for(let i in obj){
        if(obj.hasOwnProperty(i)){
            tmp[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
         }
    }
    return tmp;
}