js中深拷贝的几种方式

2,604 阅读3分钟

方式一:slice()方法

slice(start, end)方法是用来对数组进行切割,如果不传入任何参数,就会返回一个长度与原数组相同的新数组,这种方式可以实现深拷贝。

缺点:该方法只能对一维数组有效,对多维数组及对象都无效。

因此该方法只能实现一级深拷贝, 二级及以上为浅拷贝


方式二:Object.assign()方法

Object.assign(target, source1, source2)方法是ES6中提供的深拷贝方法,主要用于对对象的合并,将源对象的所有可以枚举的属性,复制到目标对象,返回合并后的对象。

缺点:该方法只能用来拷贝只有一级的对象,若对象中的子项含有对象或者数组,此方法也会无效。

因此该方法只能实现一级深拷贝, 二级及以上为浅拷贝

方式三:concat()方法

concat(arr, arr1, arr2, ...)方法用来连接多个数组,该方法不会改变现有数组,会返回被连接数组的一个副本,也可以实现深拷贝。

缺点:该方法只能对一维数组有效,对多维数组及对象都无效。

因此该方法只能实现一级深拷贝, 二级及以上为浅拷贝

方式四:使用展开运算符(ES6数组、ES7对象)

var arr=[1,2,3]
var ary=[...a];
ary.push(4);
console.log(ary);//1,2,3,4
console.log(arr)//1,2,3

缺点:使用这种方式对数组或者对象进行拷贝时,只能扩展和深拷贝第一层的值,对于第二层及以后的值,扩展运算符不能够对其进行打散扩展,也不能对其进行深拷贝,因此拷贝后和拷贝前第二层中的对象或者数组仍然引用的是同一个地址,其中一方改变,另一方也跟着改变。

因此该方法只能实现一级深拷贝, 二级及以上为浅拷贝

方式五:使用JSON的stringify和parse方法

function getValue(obj) {
    let tmp = JSON.stringify(obj); 
    let result = JSON.parse(tmp); 
    return result;
}

缺点:对于对象中的方法属性 和对象中的值为undefined的属性无法拷贝

方式六:递归方法

//使用递归的方式实现数组、对象的深拷贝
function deepClone (obj) { 
   if (obj === null || typeof obj !== 'object') return obj 
   // 判断当前参数类型 ==> 数组拷贝 || 对象拷贝  
   const copyObj = Array.isArray(obj) ? [] : {}  
   // for...in 遍历对象返回的对象的key值,遍历数组返回的数组的下标(key) 
   for (let key in obj) { 
     if (obj[key] && typeof obj[key] === 'object') { 
        copyObj[key] = deepClone(obj[key])    
     } else { 
        copyObj[key] = obj[key]  
     }  
   }  
   return copyObj
}

该方法可以实现深拷贝,对象中包含null、undefinde、function、RegExp等特殊的值也全部拷贝成功了,而且修改里边的值也不会有任何问题。

缺点:该方法无法解决循环引用问题。

方式六(优化):递归方法--解决循环引用问题

//使用递归的方式实现数组、对象的深拷贝
function deepClone (obj) {
    if (obj === null || typeof obj !== 'object') return obj
    // 记录被拷贝的值,避免循环引用出现    
    const data = {}    
    // debugger    
    function baseClone (value) { 
        // 判断当前参数类型 ==> 数组拷贝 || 对象拷贝
        const copyObj = Array.isArray(value) ? [...value] : {...value}
        // for...in 遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)
        for (let key in copyObj) {
            if (copyObj[key] && typeof copyObj[key] === 'object') {
                if (data[copyObj[key]]) {
                    copyObj[key] = data[copyObj[key]]
                } else {
                    data[copyObj[key]] = copyObj[key]
                    copyObj[key] = baseClone(copyObj[key])
                }            
        }
        return copyObj
    }
    return baseClone(obj)
}

到这里就实现了一个简单的深拷贝的方法,其实还有好多问题没有解决,比如正则、日期等等,这只是关于深拷贝的一个大致思路[抱拳][抱拳]。

方式七:借助其他库或者插件提供的方法

1、通过jQuery的extend方法实现深拷贝

2、lodash函数库实现深拷贝

3、......