前置知识
-- js的一般数据类型的存储
String Number Boolean Null Undefined
-- js的引用类型的数据存储
Object
1. 赋值
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
var obj = {}
var person = {
name:'张三',
hobby:['学习',['看电影','吃饭'],'跑步']
}
var person1 = person
person1.name = '小波'
person1.hobby[0] = '王者'
console.log(person)
console.log(person1)
运行结果:
2. 浅拷贝
重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会互相影响。
var obj = {}
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)
运行结果:
3. 深拷贝
从堆内存中开辟一个新的区域存放新对象,对对象的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
var obj = {}
var person = {
name:'张三',
hobby:['学习',['看电影','吃饭'],'跑步']
}
function deepClone(obj){
// var cloneObj = {} 就等于下面的写法
var cloneObj = new obj.constructor();
if (typeof obj === null) return obj
// if( A instanceof B) // 用来判断A是否是B的实例对象或者B子类的实例对象
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
if (typeof obj !== 'object') return obj
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)
运行结果:
总结
和原始数据是否指向同一对象 | 第一层数据为一般数据类型 | 第一层数据不是一般数据类型 | |
---|---|---|---|
赋值 | 是 | 改变会使原始数据一同改变 | 改变会使原始数据一同改变 |
浅拷贝 | 否 | 改变不会使原始数据一同改变 | 改变会使原始数据一同改变 |
深拷贝 | 否 | 改变不会使原始数据一同改变 | 改变会使原始数据一同改变 |
// 浅拷贝的实现方式
Object.assign()
... 扩展运算符
concat
lodash clone
// 深拷贝是实现方式
$.extend
deepClone
递归
JSON.parse()