javascript的深拷贝和浅拷贝问题几乎是面试必问的问题。好记性不如烂笔头,特此来记录一下本身对深拷贝浅拷贝的理解。javascript
顾名思义,拷贝就是copy复制,在js中能够浅而理解为对一个对象或者数组的复制。可是复制后的对象或者数组是不是和原来的对象指向同一个地址内存仍是新开辟了一个地址内存,这就衍生出了javascript的深拷贝和浅拷贝的问题了;深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来讲,浅复制只复制一层对象的属性,而深复制则递归复制了全部层级。java
1、javascript浅拷贝面试
浅拷贝:只复制一层对象属性,能够理解为,只复制对象的基本属性类型,而基本属性类型是存放在栈内存中的,能够直接修改访问的,因此当浅拷贝时,拷贝的对象只是拷贝了原对象的属性,而值都是指向同一个栈内存中的数据,当对象属性值发生修改时,原对象也会被修改。以下示例:正则表达式
let arr1 = { color:'red', name:'apple', weight:'100g', detail:{ big:'true', eating:'no' } }; let arr2; arr2 = arr1; arr2.color = 'black'; console.log(arr2); console.warn(arr1);
输出值:数组
能够看到,当arr2的color发生变化时,被复制的对象arr1的color值也发生了变化。app
可是在实际项目应用中,咱们复制了某个对象以后绝大多数状况下都是不但愿被复制的对象的值会发生变化,这里就涉及到javascript的深拷贝问题以及他的实现。函数
2、javascript深拷贝性能
深拷贝:它不只将原对象的各个属性逐个复制出去,并且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面 obj 和 shallowObj 的 arr 属性指向同一个对象的问题。这是我从某官网看来的解释,我感受挺绕的,结合对象来看,深拷贝存在于对象这种引用类型中,而引用类型的数据是存在堆内存上的,变量保存的是一个指针,这个指针指向另外一个位置。当须要访问引用类型(如对象,数组等)的值时,首先从栈中得到该对象的地址指针,而后再从堆内存中取得所需的数据。深拷贝能够看作是在堆内存中新开辟了一个内存空间,复制后的对象的属性所指的指针会指向新开辟的内存空间的地址。因此复制后的对象对属性值进行修改不会影响原对象的属性值。spa
那如何实现深拷贝呢?3d
一、经过JSON.parse(JSON.stringify(arr))接上面的例子:
let arr3 = JSON.parse(JSON.stringify(arr1)); arr3.color="balck"; console.log(arr3); console.warn(arr1);
输出结果:
这个方法我以为是最简洁的,可是它有一些弊端:
a、对于正则表达式类型、函数类型等没法进行深拷贝(并且会直接丢失相应的值)
b、深拷贝以后,无论这个对象原来的构造函数是什么,在深拷贝以后都会变成Object
c、若是对象中存在循环引用的状况也没法正确处理。
二、经过for循环递归调用
function deepClone(obj){ //判断obj是不是数组 let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,若是是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //若是不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; } var arr4 = deepClone(arr1); arr4.name='bananer'; console.log(arr4); console.warn(arr1);
输出结果:
可是,这样的深拷贝进行的循环递归调用,若是对象数据量庞大显然会影响性能,因此通常在项目中不多使用,循环进行深拷贝,能够考虑其余方式来实现对象值的复制引用。
三、数组concat方法
let arr4 = [1,2,3] let arr5 = [].concat(arr4) arr5.push(4) console.log(arr4, arr5, 'deep copy') // [1,2,3] [1,2,3,4]
四、js扩展运算符(...)
let arr8 = [1,2,3] let arr9 = [...arr8] arr9.push(4) console.log(arr8, arr9, 'deep copy 2') // [1,2,3] [1,2,3,4]