javascript中复制一个对象有深复制和浅复制两种方式,二者的区别的浅复制只会复制对象的第一层属性,如果对象的层级比较深且为对象或数组时,那么原对象和目标对象的深层对象或数组会指向内存中同一个对象的实例,修改其中一个也会导致另一个改变。
深复制则是会复制对象的所有层级的所有属性,在堆内存中重新分配内存,将目标对象指向新的内存空间,这样源对象和目标对象之间没有任何关联,修改其中一个也不会导致另一个被修改。
浅复制的方式
1、遍历对象
function clone(obj) { if (obj == null || typeof obj !== 'object') return obj var newObj = Array.isArray(obj) ? [] : {} for (let i in obj) { if (obj.hasOwnProperty(i)) { newObj[i] =obj[i] } } return newObj}
2、Object.assign
var obj2 = Object.assign({}, obj)
Object.assign是ES6新增的一个浅复制对象的方法,
深复制的方式
1、jQuery的$.extend方法
$.extend(true, {}, obj)
jQuery的extend方法可以浅复制对象,根据文档,在extend的第一个参数传入true可以实现深复制
2、lodash的_.方法
var objects = [{ 'a': 1 }, { 'b': 2 }]; var deep = _.cloneDeep(objects);console.log(deep[0] === objects[0]); //false
3、JSON对象的方法
var obj2 = JSON.parse(JSON.stringify(obj1))
熟悉js的人对这两个方法肯定不陌生,利用原生JSON对象的两个可以非常方便地实现对象的深复制。
这种方法也有弊端:
- 只能复制能用json表示的属性,比如String、Number、Array等,对于不能用json表示的属性例如Function、Regexp等则会丢失
- 对象的原型链丢失
- 复制效率较低
虽说有以上缺点,但是这种方式也足以应对大部分情况了。
4、递归复制
function cloneDeep(obj) { if (obj == null || typeof obj !== 'object') return obj var newObj = Array.isArray(obj) ? [] : {} for (let i in obj) { if (obj.hasOwnProperty(i)) { var value = obj[i] newObj[i] = typeof value === 'object' ? clone(value) : value } } return newObj}
这种方式与上面浅复制的遍历对象方式相比只是多了递归调用,即判断对象的属性是否也为对象,是则递归调用遍历这个对象,直到不为对象为止。
但是这种方式也没有考虑Function、Regexp、Error等类型,需要更多的判断,但是核心思想也还是递归遍历对象复制,另外这种方式比JSON的深复制效率稍高。