一、浅拷贝和深拷贝
(1)基本类型
5种基本数据类型,Number、String、Boolean、Null以及Undefined,变量是直接按值存放的,存放在栈内存中的简单数据,可以直接访问。
(2)引用类型
存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。
当需要访问引用类型(比如对象,数组)时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。
浅拷贝
如下面代码所示:
var x = { a:1, b:2 }; var y = x; y.a = 3; console.log(x);//{a: 3, b: 2} console.log(y);//{a: 3, b: 2}
这是浅拷贝,x和y指向的是同一个堆,对象复制只是复制的对象的引用。
复制的副本其实只是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受影响。
深拷贝
如下面代码所示:
var x = { a:1, b:2 }; var y = { a:x.a, b:x.b }; y.a = 3; console.log(x);//{a: 1, b: 2} console.log(y);//{a: 3, b: 2}
x对象和y对象是虽然所有的值都是一样的,但是在堆里面,对应的不是同一个了。
深拷贝和浅拷贝的示意图如下:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
二、浅拷贝的实现方式
1.通过赋值实现
将浅拷贝封装成一个函数,如下代码所示:
function shallowCopy (src) { var result = {}; for(let prop in src){ result[prop] = src[prop]; } return result; } var obj = { a:1, arr:[2,3] }; var shallowObj = shallowCopy(obj); shallowObj.arr[1] = 5; console.log(obj); console.log(shallowObj);
结果如下图所示:
2.通过Object.assign()实现
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
如下面代码所示:
var x = { a:{ b:1, c:2 } }; var y = Object.assign({},x); y.a.b = 3; console.log(x);//{a:{b:3,c:2}} console.log(y);//{a:{b:3,c:2}}
注意:当object只有一层的时候,是深拷贝,如下代码所示:
var x = { a:1, b:2 }; var y = Object.assign({},x); y.a = 3; console.log(x);//{a: 1, b: 2} console.log(y);//{a: 3, b: 2}
三、深拷贝的实现方式
1.当对象只有一层时,通过Object.assign()实现,如上
2.JSON对象的stringify以及parse方法
JSON.stringify方法将js对象序列化成JSON字符串,JSON.parse方法将JSON字符串反序列化为js对象。
借助这两个方法,可以实现对象的深拷贝。
var x = { a:1, b:2 }; var y = JSON.parse(JSON.stringify(x)); y.a = 3; console.log(x);//{a: 1, b: 2} console.log(y);//{a: 3, b: 2}
3.jQuery 的$.extend方法
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