本文参考:
浅拷贝
最简单的浅拷贝就是赋值操作
var obj1 = ['lee', {age: 22}];
var obj2 = obj1;
obj2[0] = 'json';
console.log(obj1[0]); // json
obj2[1].age = 20;
console.log(obj1[1].age); // 20
- 对于基本数据类型,两个变量不会相互影响
- 对于引用数据类型,两个变量共用同一块堆内存,会相互影响
浅拷贝是只复制第一层得到的新实例
var obj1 = ['lee', {age: 22}];
var obj2 = obj1.slice();
obj2[0] = 'json';
console.log(obj1[0]); // lee
obj2[1].age = 20;
console.log(obj1[1].age); // 20
- 对于基本数据类型,会在堆中重新开辟一块内存,修改后不会相互影响
- 对于引用数据类型,因为只拷贝了一层,所以指针还是指向同一块堆内存,会相互影响
深拷贝
深拷贝是递归复制了所有层级得到的新实例
var obj1 = ['lee', {age: 22}];
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2[0] = 'json';
console.log(obj1[0]); // lee
obj2[1].age = 20;
console.log(obj1[1].age); // 22
- 由于对整个对象及其子对象进行了递归复制,所以无论是基本数据类型还是引用数据类型,内存上都会重新创建,两个对象不会相互影响
实现方法
数组浅拷贝
Array.prototype.slice()
var obj1 = ['lee', {age: 22}];
var obj2 = obj1.slice();
Array.prototype.concat()
var obj1 = ['lee', {age: 22}];
var obj2 = obj1.concat();
Array.from(obj)
var obj1 = ['lee', {age: 22}];
var obj2 = Array.from(obj1);
Array.prototype.map(callback)
var obj1 = ['lee', {age: 22}];
var obj2 = obj1.map(item => item);
浅拷贝
-
Object.assign([], obj)
或Object.assign({}, obj)
var obj1 = ['lee', {age: 22}];
var obj2 = Object.assign([], obj1);
var obj1 = { a: 0, b: { c: 0 } };
var obj2 = Object.assign({}, obj1);
-
[...obj]
或{...obj}
var obj1 = ['lee', {age: 22}];
var obj2 = [...obj1];
var obj1 = { a: 0, b: { c: 0 } };
var obj2 = {...obj1}
自己动手实现
function shallowClone (obj) {
if (!obj || typeof obj !== 'object') {
throw new Error('arguments error');
}
var targetObj = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
targetObj[key] = obj[key];
}
}
return targetObj;
}
-
jQuery.extend([], obj)
或jQuery.extend({}, obj)
var obj1 = ['lee', {age: 22}];
var obj2 = $.extend([], obj1);
var obj1 = { a: 0, b: { c: 0 } };
var obj2 = $.extend({}, obj1);
lodash.clone(obj)
var obj1 = ['lee', {age: 22}];
var obj2 = _.clone(obj1);
var obj1 = { a: 0, b: { c: 0 } };
var obj2 = _.clone(obj1);
深拷贝
JSON.parse(JSON.stringify(obj))
var obj1 = ['lee', {age: 22}];
var obj2 = JSON.parse(JSON.stringify(obj1));
缺点:由于
JSON.stringify()
方法在序列化JS
对象时,会忽略所有函数和原型成员,导致拷贝丢失。
这种实现方法能够处理JSON
格式所能表示的所有数据类型,但是对Regexp
、Function
等类型无法进行深拷贝,同时也无法正确处理对象内部循环应用的问题。
自己动手实现
function deepClone(obj) {
if (!obj || typeof obj !== 'object') {
throw new Error('arguments error');
}
var targetObj = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
targetObj[key] = Array.isArray(obj[key]) ? [] : {};
targetObj[key] = deepClone(obj[key]);
} else {
targetObj[key] = obj[key];
}
}
}
return targetObj;
}
缺点:与
jQuery
中的extend
方法实现思路一样,不能处理对象内部循环引用的问题,对Date
、Function
类型的值没有实现真正的深拷贝,但这些类型的值重新定义时,一般都是直接覆盖,不会影响原对象,所以从一定程度上来讲也算是实现了深拷贝。
-
jQuery.extend(true, [], obj)
或jQuery.extend(true, {}, obj)
var obj1 = ['lee', {age: 22}];
var obj2 = $.extend(true, [], obj1);
var obj1 = { a: 0, b: { c: 0 } };
var obj2 = $.extend(true, {}, obj1);
jQuery.extend 源码实现
缺点:无法处理对象内部循环引用的问题
lodash.cloneDeep(obj)
var obj1 = { a: 0, b: { c: 0 } };
var obj2 = _.cloneDeep(obj1)
网友评论