说在前面
这是一个系列的文章,有兴趣的朋友可以查看此系列其它文章(持续更新ing)。本人才疏学浅,若有纰漏还请及时指出,请多指教!
情境描述
面试官:你了解js的深拷贝和浅拷贝吗?
我:深拷贝是连同引用地址和值一起拷贝;浅拷贝是只拷贝引用地址,不拷贝值,共用内存。
面试官:那浅拷贝和深拷贝如何实现?
我:用Object.create()实现深拷贝,(此处过了20秒钟),。。。
面试官:还有吗?
我:uhhhh,。。。忘了。。
面试官:那好,下一个问题。。。
(真想找个地洞钻进去。。。)
上面情景是大多数面试者都经历的事情,可是不能每次都被问倒呀,或许面试结束网上一搜就有解释,可是看一遍怎么会记得住呢?不妨记下来吧。
正题
深拷贝:复制了引用地址和值,相当于复制了一份副本,值相同,地址不同,互不影响。
浅拷贝:仅仅是复制了引用地址,也就是说新变量和旧变量共用内存,彼此的修改会互相影响。
1、如何实现深拷贝?
(1)手动赋值
var obj1 = {a: 1, b: 2}; var obj2 = {a: obj1.a, b: obj1.b}; obj2.a = 0; console.log(obj1.a); // 1 obj1.a = 3; console.log(obj2.a); // 0
(2)JSON
用JSON.stringify将对象转为字符串,再用JSON.parse将字符串转为对象。
var obj1 = {a: 1, b: 2}; var obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj2); // {a: 1, b: 2} obj2.a = 3; console.log(obj1.a); // 1,不受影响
ps:只有能被转为json格式的对象才能这样用。
(3)Object.create
var obj1 = {a: 1, b: 2}; var obj2 = Object.create(obj1); obj2.a = 3; // 在obj2的原型上访问属性 console.log(obj1.a); // 1,不受影响
(4)递归拷贝
还没实现,下次更新。。。。
2、如何实现浅拷贝?
(1)赋值操作符(=)
对于(Boolean、String、Number、Undefined、Null)这五种基本数据类型,它们的复赋值是值传递,而对于对象的赋值是对引用赋值,所以使用“=”赋值对象就是对对象的浅拷贝。
var obj = { a: 1, b: 2 } var obj1 = obj; obj1.a = 3; console.log(obj.a); // 3,被改了 obj.b = 0; console.log(obj1.b); // 0,也被改了
(2)对象的解构赋值
var obj1 = {a: 1, b: {c: 2}}; var obj2 = {...obj1}; obj2.b.c = 3; console.log(obj1.b.c); // 3 obj1.b.c = 0; console.log(obj2.b.c); // 0
(3)Object.assign()
此方法是ES6中定义的方法,用于将源对象的所有可枚举属性复制到目标对象中,返回值是目标对象。用法如下:
Object.assign(targetObj, sourceObj1, ...sourceObjn);
例子:
let sourceObj = { a: { b: 1}}; let targetObj = {c: 3}; Object.assign(targetObj, sourceObj); sourceObj.a.b = 2; console.log(targetObj.a.b); // 2, 源对象的修改影响到了目标对象 targetObj.a.b = 4; console.log(sourceObj.a.b); // 4, 目标对象的修改影响到了源对象
但是我发现一个奇怪的现象,如下所示:
obj的属性a竟然没有被修改,说明对于第一层属性,Object.assign是深拷贝。
参考资料
JSON教程https://www.runoob.com/json/json-tutorial.html
ES6对象https://www.runoob.com/w3cnote/es6-object.html