在JS中一切都是对象,分为原始类型和合成类型:
原始类型:Undefined、Null、Boolean、String、Number,按值传递
合成类型:array、object和function,按内存中的地址传递。
浅克隆:基本类型按值传递,对象是引用传递;
深克隆:所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。
用 Object.assign
, JSON.stringify
和 JSON.parse
方法去克隆一个对象,这个可以明确告诉大家这些都是些不靠谱的浅度克隆。
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
//例1var 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); //targettarget.child.name = "target child"; //改变target的child console.log(source.child.name); //child console.log(target.child.name); //target child//例2var source = { name:function(){console.log(1);}, child:{ name:"child" } } var target = JSON.parse(JSON.stringify(source));console.log(target.name); //undefined//例3var source = { name:function(){console.log(1);}, child:new RegExp("e") }var target = JSON.parse(JSON.stringify(source));console.log(target.name); //undefinedconsole.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;}复制代码