说起js引用类型,绕不开的点就是浅拷贝和深拷贝。
一、赋值(=)与浅拷贝
什么是赋值?什么又是浅拷贝?(只针对引用类型)
赋值就是将引用类型的引用地址赋予到变量上保存的过程
浅拷贝是对所引用的对象做一次一级拷贝赋值到新的变量上,下面用代码来进行演示
var obj = {
name: 'eric',
age: 26,
language: ['chinese', 'english']
}
var obj1 = obj // 赋值
var obj2 = simpleClone(obj)
function simpleClone (obj) {
var ret = {}, key
for (key in obj) {
if(obj.hasOwnProperty(key)) {
ret[key] = obj[key]
}
}
return ret
}// 得到的三个变量的值为:
// obj = {
// name: 'eric',
// age: 26,
// language: ['chinese', 'english']
// }
// obj = {
// name: 'eric',
// age: 26,
// language: ['chinese', 'english']
// }
// obj = {
// name: 'eric',
// age: 26,
// language: ['chinese', 'english']
// }obj.name = 'super6'
obj.sex = 'man'
console.log(obj1.name) // super6
console.log(obj1.sex) // man
console.log(obj2.sex) // undefined
obj.language.push('japanese')
console.log(obj.language) // ['chinese', 'english', 'japanese']
console.log(obj1.language) // ['chinese', 'english', 'japanese']
console.log(obj2.language) // ['chinese', 'english', 'japanese']总结就是,浅拷贝就是将一个对象a中第一级的键值对拷贝到新的变量b中,传值的过程,基本类型传值,引用类型传址。a与b在堆内存是不同的存储地址。
二、深拷贝
深拷贝就是将一个对象a完全的拷贝到新变量b中,这其中包含了对象a中的子对象
JS原生不支持深拷贝,Object.assign和{...obj}都属于浅拷贝。
JSON.stringfy和JSON.parse
js中实现深拷贝的最简单的方法了,原理也简单:就是将对象转换为字符串,然后再通过JSON.parse新建一个对象,但是这种方法也有他的局限性:
1、不能复制function、正则和Symbol
2、循环引用报错
3、相同的引用会被重复复制
①
let obj = {
reg : /^abc$/,
fun: function(){},
syb:Symbol('stttr'),
asd:'abc'
};
let cp = JSON.parse(JSON.stringify(obj));
console.log(cp);打印的结果:

正则、Symbol和function都没有被正确的复制
②
③
var obj = {
name: 'eric',
age: 26
}
var lang = ['chinese', 'english']
obj.lang = lang
obj.language = lang
var cp = JSON.parse(JSON.stringify(obj))
obj.lang.push('japanese')
cp.lang.push('japanese')
console.log(obj.language)
console.log(cp.language)obj.language // ['chinese', 'english', 'japanese']
cp.language // ['chinese', 'english']我们期望的结果是cp中的lang和language依然是指向的同一个堆数据,但是JSON实现深克隆的过程中lang和language分别指向了不同的堆数据(对象)
递归实现深拷贝
对于这种嵌套对象的拷贝,我们很容易就会想到递归。
思路也是很简单的:对于简单类型,直接复制。对于引用类型,递归复制它的每一个属性。
同时我们需要解决的问题:
1、循环引用
2、相同引用
3、不同的类型
function deepClone (o) {
let copyList = []
function _deepC (o) {
if (typeof o !== 'object' || !o) return o
for (let i = 0, len = copyList.length; i < len; i++) {
if (copyList[i].taget === o) {
return copyList[i].copyTarget
}
}
let obj = {}
if (Array.isArray(o)) {
obj = []
}
copyList.push({
target: o,
copyTarge: obj
})
Object.keys(o).forEach(key => {
if (obj[key]) return
obj[key] = _deepC(o[key])
})
return obj
}
return _deepC(o)
}