前言:最近在复习一些面试的知识点,刚刚好复习到了这一部分,于是就写下这篇文章记录一下。
一 、值类型和引用类型
在学习深拷贝和浅拷贝之前,我们先来了解一下js的变量类型。
值类型 vs 引用类型
值类型:值类型主要有:number,string,boolean,symbol,null,undefined 这6种。
我们来看下代码:
我们可以看到将a赋值给了b,然后将a的值改变,再打印b,发现b还是100.
引用类型:Object,Array,RegExp,Date,Function。
看下代码:
a为一个对象,里面有age,将b赋值成a,然后修改b.age,发现a对象里面的age也跟着改变了。
深入分析一下:
1、当我们的代码中出现变量的时候,浏览器会将变量存放栈中,这个栈就是我们计算机的储存结构。如上面值类型中的定义的变量a和b,就会放到栈中存储起来。
由上图可以看到,当重新定义变量b,并且将b赋值为a的时候,栈就会重新开辟一个储存位置,这时候改变b的值,是不会影响到a变量的值得的。
2、当我们使用到js的引用类型变量的时候,这时候就会涉及到堆的储存(在计算机变量存储的时候,堆和栈是同时存在的,栈是从上往下累加,堆是相反)。
当我们将变量a赋值成一个对象的时候,浏览器会在堆中生成一个内存地址(内存地址1),然后把这个对象{age :18},放到堆里面存储起来。这时候,变量a存储的是一个地址,并且在栈中储存起来。这时候将变量b赋值成a,b就会同样的指向内存地址1。这时候去改变b的内容,a中的内容也是会发生改变的。这是因为b拷贝了a在栈中的堆地址,都指向a在堆中的属性值,当a放生改变时,b属性值也会改变,因为b也指向相同的堆内存。
那么有没有办法将 引用类型 像 值类型 赋值一样去赋值呢?
接下来就需要用到js的浅拷贝和深拷贝了来解决上面出现的问题了(而变量 a和 b 指向同一地址,当该地址的数据改变时,所有使用该地址的变量全部改变(同一数据))。
浅拷贝
既然对象数据类型 是由基本数据类型组成的,而基本数据类型可以正常赋值、比较,那我们就把对象类型变成一个个的基本类型进行操作,所以我们可以遍历对象中的内容,一个一个的进行赋值,进行一层的拷贝,这就是浅拷贝。下面我们来手写一个浅拷贝
//浅拷贝 function shallowClone(source = {}) { let result = {}, key; for(key in source){ if (source.hasOwnProperty(key)) { //这里的意思是判断这一项是否是其自有属性,是的话才拷贝,不是就不拷贝 result[key] = source[key] } } return result; }
然后我们来测试一下,发现是拷贝成功了,
但是这只能拷贝一层,要是对象有多层嵌套的话,就不行了。如下:
这时候,我们需要使用到深拷贝来解决这个问题。
深拷贝
相对于浅拷贝只能拷贝一层,深拷贝可以无限层次的拷贝。
深拷贝实现的思路:
深拷贝,就是遍历那个被拷贝的对象
判断对象里每一项的数据类型
如果不是对象类型,就直接赋值,如果是对象类型,就再次调用deepCopy,递归的去赋值。
代码如下:
// 深拷贝 function deepClone(source = {}) { if (typeof source !== 'object' || source == null) { // source为null,或者不是数组和对象,直接返回 return source; } // 初始化返回结果 let result; if (source instanceof Array) { result = []; } else { result = {}; } for (let key in source) { //这里的意思是判断这一项是否是其自有属性,是的话才拷贝,不是就不拷贝 if (source.hasOwnProperty(key)) { // 递归调用 result[key] = deepClone(source[key]) } } return result; }
然后我们来测试一下:
会发现,深拷贝成功了。
还有一种非常简单的深拷贝方法,相信大家也经常用到过,就是使用系统自带的JSON来做深拷贝。
function cloneJSON(source) { return JSON.parse(JSON.stringify(source)); }
但是他的缺陷就是:对象里面的函数无法被拷贝,原型链里面的属性无法被拷贝。
总结
其实我们有很多其他的办法实现拷贝,比如:ES6的assign方法(浅拷贝);通过immutableJS实现深拷贝; JQ的extend方法等等。我们可以根据不同的业务场景进行不同的选择。无论是深拷贝还是浅拷贝,一旦数据量大了起来,都会出现性能问题。