深拷贝:修改新变量的值不会影响原有变量的值。默认情况下基本数据类型(number,string,null,undefined,boolean)都是深拷贝。
浅拷贝:修改新变量的值会影响原有的变量的值。默认情况下引用类型(object)都是浅拷贝。
- 解构赋值,如果所解构的原对象是一维数组或对象,其本质就是对基本数据类型进行等号赋值,那它就是深拷贝;
- 如果是多维数组或对象,其本质就是对引用类型数据进项等号赋值,那它就是浅拷贝;
深拷贝的实现方法
本质还是将对象拆开为基本数据类型进行赋值。
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source){ // 遍历目标
if(source.hasOwnProperty(keys)){
if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
第三方库实现深拷贝
jQuery的$.extend()
我们可以通过$.extend()
方法来完成深复制。值得庆幸的是,我们在jQuery
中可以通过添加一个参数来实现递归extend
。调用$.extend(true, {}, ...)
就可以实现深复制
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = $.extend({}, x), //shallow copy
z = $.extend(true, {}, x); //deep copy
y.b.f === x.b.f // true
z.b.f === x.b.f // false
但是jQuery
的这个$.extend()
方法,有弊端
var objA = {};
var objB = {};
objA.b = objB;
objB.a = objA;
$.extend(true,{},a);
//这个时候就出现异常了
//Uncaught RangeError: Maximum call stack size exceeded(…)
也就是说,jQuery
中的$.extend()
并没有处理循环引用的问题。
使用JSON对象实现深拷贝
使用JSON
全局对象的parse
和stringify
方法来实现深复制也算是一个简单讨巧的方法。
function jsonClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
var clone = jsonClone({ a:1 });
然而使用这种方法会有一些隐藏的坑,它能正确处理的对象只有 Number
, String
, Boolean
, Array
, 扁平对象,即那些能够被 json
直接表示的数据结构。