浅拷贝
var m = {a: 10, b: 20}
var n = m;
n.a = 15; // 这时 m.a 的值是多少
m.a 会输入 15,因为这是浅拷贝,n 和 m 指向的是同一个堆,对象复制只是复制的对象的援用。
深拷贝
var m = {a: 10, b: 20}
var n = {a:m.a,b:m.b};
n.a = 15;
深拷贝和下面浅拷贝不同,就是彻底 copy 一个对象,而不是 copy 对象的援用。
这次,咱们再来输入 m.a,发现 m.a 的值还是 10, 并没有扭转,m 对象和 n 对象是尽管所有的值都是一样的,然而在堆外面,对应的不是同一个了,这个就是深拷贝。
深拷贝和浅拷贝
深拷贝和浅拷贝的示意图大抵如下:
浅拷贝只复制指向某个对象的指针,而不复制对象自身,新旧对象还是共享同一块内存。但深拷贝会另外发明一个截然不同的对象,新对象跟原对象不共享内存,批改新对象不会改到原对象。
浅拷贝的实现形式
1、能够通过简略的赋值实现
function simpleClone(initalObj) {var obj = {};
for (var i in initalObj) {obj[i] = initalObj[i];
}
return obj;
}
var obj = {
a: "hello",
b:{a: "world", b: 21},
c:["Bob", "Tom", "Jenny"],
d:function() {alert("hello world");
}
}
var cloneObj = simpleClone(obj);
console.log(cloneObj.b);
console.log(cloneObj.c);
console.log(cloneObj.d);
cloneObj.b.a = "changed";
cloneObj.c = [1, 2, 3];
cloneObj.d = function() {alert("changed");
};
console.log(obj.b);
console.log(obj.c);
console.log(obj.d);
2、Object.assign() 实现
Object.assign() 办法能够把任意多个的源对象本身的可枚举属性拷贝给指标对象,而后返回指标对象。然而 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的援用,而不是对象自身。
var obj = {a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"
留神:当 object 只有一层的时候,是深拷贝,例如如下:
var obj1 = {a: 10, b: 20, c: 30};
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// {a: 10, b: 20, c: 30} <-- 沒被改到
console.log(obj2);
// {a: 10, b: 100, c: 30}
3、函数库 lodash 的_.clone 办法
该函数库也有提供_.clone 用来做 Shallow Copy, 前面咱们会再介绍利用这个库实现深拷贝。
var _ = require('lodash');
var obj1 = {
a: 1,
b: {f: { g: 1} },
c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f);// true
4、开展运算符 …
开展运算符是一个 es6 / es2015 个性,它提供了一种十分不便的形式来执行浅拷贝,这与 Object.assign () 的性能雷同。
let obj1 = {name: 'Kobe', address:{x:100,y:100}}
let obj2= {... obj1}
obj1.address.x = 200;
obj1.name = 'wade'
console.log('obj2',obj2) // obj2 {name: 'Kobe', address: { x: 200, y: 100} }
5、Array.prototype.concat()
let arr = [1, 3, {username: 'kobe'}];
let arr2 = arr.concat();
arr2[2].username = 'wade';
console.log(arr); //[1, 3, { username: 'wade'} ]
6、Array.prototype.slice()
let arr = [1, 3, {username: 'kobe'}];
let arr3 = arr.slice();
arr3[2].username = 'wade'
console.log(arr); // [1, 3, { username: 'wade'} ]
深拷贝的实现形式
1、办法一还是手动复制
和下面的举例一样,手动复制能够实现深拷贝。
2、对象只有一层的话能够应用下面的:Object.assign() 函数
3、转成 JSON 再转回来
var obj1 = {body: { a: 10} };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// {body: { a: 10} } <-- 沒被改到
console.log(obj2);
// {body: { a: 20} }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false
用 JSON.stringify 把对象转成字符串,再用 JSON.parse 把字符串转成新的对象。
能够封装如下函数
var cloneObj = function(obj){var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){return;} else if(window.JSON){str = JSON.stringify(obj), // 系列化对象
newobj = JSON.parse(str); // 还原
} else {for(var i in obj){newobj[i] = typeof obj[i] === 'object' ?
cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};
4、函数库 lodash 的_.cloneDeep 办法
该函数库也有提供_.cloneDeep 用来做 Deep Copy
var _ = require('lodash');
var obj1 = {
a: 1,
b: {f: { g: 1} },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
5、递归拷贝
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 str = {};
var obj = {a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
6、应用 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;
}
7、jquery
jquery 有提供一个 $.extend 能够用来做 Deep Copy。
var $ = require('jquery');
var obj1 = {
a: 1,
b: {f: { g: 1} },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);
// false
8、lodash
另外一个很热门的函数库 lodash,也有提供_.cloneDeep 用来做 Deep Copy。
var _ = require('lodash');
var obj1 = {
a: 1,
b: {f: { g: 1} },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false