前端的浅拷贝和深拷贝
一、什么是浅拷贝、什么是深拷贝
最近自己面试被问到浅拷贝、深拷贝,关键是自己一时回答不上了,所以恶补一下。
我们都知道js的数据类型分为基本类型和引用类型,一般讨论到浅拷贝和深拷贝的都是针对引用类型的,像Object和Array这样的复杂类型
1、浅拷贝:以Object为例
var a = { name: 'liner' }; var b = a; b.name = 'Jiejie'; console.log(b.name); // Jiejie console.log(a.name); // Jiejie
可以看出,对于Object类型,当我们将a赋值给b,然后更改b中的属性,a也会随着变化。
也就是说a和b指向了同一块内存,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝。
2、深拷贝
我们如果给b放到新的内存中,将a的各个属性都复制到新内存里,就是深拷贝。
也就是说,当b中的属性有变化的时候,a内的属性不会发生变化。
二、浅拷贝的实现
1、Object.assign()
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
var target = {a: 1, b: 1}; var obj1 = {a: 2, b: 2, c: {ca:1}}; var obj2 = {c: {ca: 3, cb: 2, cd: 1}}; var result = Object.assign(target, obj1, obj2); console.log(target); // {a: 2, b: 2, c: {ca: 3, cb: 2, cd: 1}} console.log(target === result); // true
可以看到,
Object.assign()
拷贝的只是属性值,假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。所以Object.assign()
只能用于浅拷贝或是合并对象。这是Object.assign()
值得注意的地方。三、深拷贝的实现
1、层级拷贝,用递归实现。
function deepClone(obj){ //定义对象来判断当前的参数是数组还是对象 let objClone = Array.isArray(obj)?[]:{}; //如果obj存在并且为对象 if(obj&&typeof obj == "object"){ for(let key in obj){ if(obj.hasOwnProperty(key)){ //如果obj的子元素为对象,那么递归(层级遍历) if(obj[key]&&typeof obj[key] == "object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,直接赋值 objClone[key] = obj[key]; } } } } return objClone; }
2、JSON解析(底层原理也是层级遍历)
var a = [0,1,2,[3,4],5]; var b = JSON.parse(JSON.stringify(a)); console.log(b); //[0,1,2,[3,4],5]; console.log(a === b); // false
b就是拷贝的结果,修改b不影响a。但是这种方法也有缺陷:
- 无法复制函数
- 原型链没了,对象就是object,所属的类没了。
一本好书,静静抱坐读到日月无光,人就在书里起伏,掩耳不听那尘世喧嚣,这世间最宁静的快乐。