前置知识
js中的常见类型:
基本类型(原始类型):number、string、boolean、null、undefind
引用类型:object
注:变量存储在栈内存中,对象存储在堆内存中。
浅拷贝:
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值。
如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
针对引用类型来说 赋值 深拷贝 浅拷贝的区别:
赋值:
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此两个对象是联动的。
赋值的例题:
我们可以看到原对象的name和hobby[0]都被改了。
浅拷贝:
重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会互相影响。
注:浅拷贝只遍历一层,并不包含子对象。
浅拷贝的例题:
我们可以看到原对象中属于基本类型的name没有被更改,而属于引用类型的hobby[0]被更改了。
深拷贝:
从堆内存中开辟一个新的区域存放新对象,对对象的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
我们可以看到原对象的name和hobby[0]均未被改变。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>浅拷贝</title>
</head>
<body>
<script>
var person = {
name: '张三',
hobby: ['学习',['看电影','购物'],['跑步']]
}
function shallowCopy(obj) {
var target = {}
for( var i in obj ) {
if(obj.hasOwnProperty(i)) {
target[i] = obj[i]
}
}
return target
}
var person1 = shallowCopy(person)
person1.name = '李四'
person1.hobby[0] = '玩耍'
console.log(person)
console.log(person1)
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>深拷贝</title>
</head>
<body>
<script>
var person = {
name: '张三',
hobby: ['学习',['看电影','购物'],['跑步']]
}
function deepClone(obj) {
var cloneObj = new obj.constructor()
if(obj ===null) return obj
if(obj instanceof Date) return new Date(obj)
if(obj instanceof RegExp) return new RegExp(obj)
if(typeof obj !== 'object') return
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
cloneObj[i] = deepClone(obj[i])
}
}
return cloneObj
}
var person1 = deepClone(person)
person1.name = '李四'
person1.hobby[0] = '玩耍'
console.log(person)
console.log(person1)
</script>
</body>
</html>
ps:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。