深入浅出:了解深拷贝和浅拷贝

Posted yunshangwuyou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入浅出:了解深拷贝和浅拷贝相关的知识,希望对你有一定的参考价值。

值传递:基本数据类型传递数据(数据发生改变的时候,另一个数据不会发生改变)
引用传递:引用数据类型传递数据,复制另一个引用数据类型的地址,所以当数据发生改变的时候,另一个引用数据类型的数据也会发生改变。因为他们的两个只想同一地址。
 1.浅拷贝:当一个对象复制另一个对象的数据后,当改变其中一个对象的数据后,另一个对象的数据也会发生改变,这就是浅拷贝;
 2.深拷贝:当一个对象复制另一个对象的数据后,当改变其中一个对象的数据后,另一个对象的数据不会发生改变,这就是深拷贝;
 (1).最简单的浅拷贝
var obj = { a: 1, b: 2, c: 3 };
var newObj = obj;
newObj.a = 10;
console.log(obj);//{a:10,b:2,c:3}
console.log(newObj);//{a:10,b:2,c:3};

(2).ES6对象的方法:Object.assign():第一个参数是目标对象,后面的参数都是源对象(需要拷贝的对象);返回值是合并后的对象。
例:当对象是多层的时候

 

var obj = { data: { a: 1, b: 2, c: 3 } };
var newObj = Object.assign({}, obj);
newObj.data.a = 10;
console.log(obj, newObj)
3、自己封装copy的方法
var obj = {
"data": { ‘a‘: ‘1‘ },
"b": "1",
"c": "2"
}
function copy(obj) {
var newObj = {};
for (var key in obj) {
newObj[key] = obj[key];
}
return newObj;
}
var newObj = copy(obj);
console.log(newObj)//{"data":{‘a‘:‘1‘},"b":"1","c":"2"}
newObj.data.a = 10;//二层对象进行的是浅拷贝
newObj.b = 50;//一层对象进行生拷贝
console.log(obj, newObj)//{"data":{‘a‘:‘10‘},"b":"1","c":"2"},{"data":{‘a‘:‘10‘},"b":"50","c":"2"}
4、$.extend({},{})
var obj = { data: { a: 1, b: 2, c: 3 } };
var newObj = $.extend({}, obj);
newObj.data.a = 10;
console.log(obj, newObj)
深拷贝
1、Object.assign()
前提是对象只有一层
var obj = { a: 1, b: 2, c: 3 };
var newObj = Object.assign({}, obj);
newObj.a = 20;
console.log(obj, newObj)
2、$.extend()
当第一个参数是true的时候是深拷贝 当不传递的时候是浅拷贝
var obj = { data: { a: 1, b: 2, c: 3 } };
var newObj = $.extend(true, {}, obj);
newObj.data.a = 20;
console.log(obj);
console.log(newObj)
3、JSON.stringify;但目标对象有要求(非 undefined,function)
var obj = { data: { a: 1, b: 2, c: 3 } };
var newObj = JSON.parse(JSON.stringify(obj));
newObj.data.a = 20;
console.log(obj);
console.log(newObj)
缺点是函数不能被赋值
4.递归方法
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
if (typeof initalObj[i] === ‘object‘) {
obj[i] = (initalObj[i].constructor === Array) ? [] : {};
arguments.callee(initalObj[i], obj[i]);
} else {
obj[i] = initalObj[i];
}
}
return obj;
}
上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。
改进版代码如下:

 

function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i];

// 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if (prop === obj) {
continue;
}

if (typeof prop === ‘object‘) {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
使用的时候这样写:
        var Doctor = deepCopy(Chinese);
        现在,给父对象加一个属性,值为数组。然后,在子对象上修改这个属性:
         Chinese.birthPlaces = [‘北京‘,‘上海‘,‘香港‘];
          Doctor.birthPlaces.push(‘厦门‘);
        这时,父对象就不会受到影响了。
        alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
          alert(Chinese.birthPlaces); //北京, 上海, 香港
        目前,jQuery库使用的就是这种继承方法。

 

5.使用Object.create()方法;直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。

function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i];

// 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if (prop === obj) {
continue;
}

if (typeof prop === ‘object‘) {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}


 

以上是关于深入浅出:了解深拷贝和浅拷贝的主要内容,如果未能解决你的问题,请参考以下文章

深入理解深拷贝和浅拷贝一篇文章就够了

深入探讨深拷贝浅拷贝两兄弟

深拷贝与浅拷贝的实现(一)

深浅拷贝——利用模拟实现basic_string深入理解

栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!

Javascript学习之深拷贝和浅拷贝详解