浅拷贝的时候是地址传递,两个对象指向的是同一个地址,修改其中一个对象里的值,另一个对象里的值也会被改变;深拷贝则是值传递,两个对象指向的是不同的地址,但是值是相同的
方法一:利用json
1 2 const cloneObj = JSON .parse(JSON .stringify(obj))
利用JSON方法来拷贝有空位的数组的时候,空位(undefined
)会被拷贝为null
方法二:递归拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function deepClone (obj, cache = new WeakMap () ) { if (obj === null || typeof obj !== 'object' ) return obj if (obj instanceof Date ) return new Date (obj) if (obj instanceof RegExp ) return new RegExp (obj) if (cache.has(obj)) return cache.get(obj) let cloneObj = new obj.constructor() cache.set(obj, cloneObj) for (let key in obj) { if (obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key], cache) } } return cloneObj }const obj = { name : 'Jack' , address : { x : 100 , y : 200 } } obj.a = obj const newObj = deepClone(obj)console .log(newObj.address === obj.address)
方法三:结合defineProperty
参考 [[属性的描述对象#对象的拷贝]]
1 2 3 4 5 6 7 8 9 10 11 12 var extend = function (to, from ) { for (var property in from ) { if (!from .hasOwnProperty(property)) continue ; Object .defineProperty( to, property, Object .getOwnPropertyDescriptor(from , property) ); } return to; }
在方法二的基础上改进属性描述对象 - JavaScript 教程 - 网道 (wangdoc.com)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var extend = function (obj ) { if (obj === null || typeof obj !== 'object' ) return obj let newobj = new obj.constructor(); for (var property in obj) { if (!obj.hasOwnProperty(property)) continue ; Object .defineProperty( newobj, property, Object .getOwnPropertyDescriptor(obj, property) ); } return newobj; }
附(最外层深拷贝):Object.assign
Object.assign
默认是对对象进行深拷贝的,但是我们需要注意的是,它只对最外层的进行深拷贝,也就是当对象内嵌套有对象的时候,被嵌套的对象进行的还是浅拷贝;
1 2 3 4 function cloneDeepAssign (obj ) { return Object .assign({},obj) }
(温馨提示:数组拷贝方法当中,使用...
、slice
、concat
等进行拷贝也是一样的效果,只深拷贝最外层)
同时,我们知道Object.assign
针对的是对象自身可枚举的属性,对于不可枚举的没有效果;
所以,当我们对于一个层次单一对象的时候,可以考虑这种方法,简单快捷。(试过了,也不支持undefined
)