引用类型的名存储在栈内存中,值存在堆内存中 栈内存的名存储着堆内存的地址
var a = {name: 'hello'}
var b = a // b拿到的是对象a的堆内存地址
console.log(a.name) // hello
b.name = 'hi'
console.log(a.name) // hi
浅拷贝:对象B拷贝对象A,对象A改变,对象B跟着改变
浅拷贝的方式:
1.上面提到的 var b = a 是一种
这种方式是彻底的浅拷贝
2. for in 循环 浅拷贝
这种方式的浅拷贝,被拷贝的对象的第一层是深层的,也就是改变拷贝对象的第一层,被拷贝对象无影响
var sample = {
aa: 'aa',
bb: { cc: 'sss' },
dd: { ee: {ff: 'ff'} }
}
function shallowclone(obj) {
let o = {}
for(let i in obj) {
o[i] = obj[i]
}
return o
}
var oo = shallowclone(sample)
oo.aa = 'sss'
console.log(sample.aa) // aa 没有改变
3.解构赋值
这种方式的浅拷贝和for in 效果一样 因为它们的实现都和迭代器有关
var oo = {...sample}
4.Object,assign()
这种方式和直接赋值效果一样
var oo = Object.assign(sample)
------------------------------------------------------------------
深拷贝
另辟内存,将被拷贝对象的值复制过来
1.JSON.stringify() 和 JSON.parse()
var sample = {
aa: 'aa',
bb: { cc: 'sss' },
dd: { ee: {ff: 'ff'} },
say: function() {}
}
var oo = JSON.stringify(sample)
oo = JSON.parse(oo)
这种方式拷贝不了被拷贝对象的方法
console.log(oo.say) // undefined
for in 浅拷贝的原因:如果有第二层,那么第二层必然是引用类型 for in 循环时
遍历了第一层的键值而已 对于第二层压根没有遍历 所以:
function deepclone(obj) {
let o = {}
for(var i in obj) {
if(typeof obj[i] === "object") {
o[i] = deepclone(obj[i])
}
else {
o[i] = obj[i]
}
}
return o
}
上面判断参数是否是对象的方法可以封装起来
function isObject(o) {
return Object.prototype.toString.call(o) === "[object object]"
}
考虑一个循环引用的问题
var a = {}
a.a = a
function deepclone1(o) {
if(! isObject(o)) return
let obj = {}
for(var i in o) {
if(isObject(o[i])) obj[i] = deepclone1(o[i]) // 进入了死循环
else obj[i] = o[i]
}
return obj
}
使用map记录 如果已经遍历 那么不再遍历
function deepclone2(o, hash = new Map()) {
if(! isObject(o)) return
if(hash.has(o)) return hash.get(o)
let obj = {}
hash.set(o, obj)
for(var i in o) {
if(isObject(o[i]) obj[i] = deepclone2(o[i], hash)
else obj[i] = o[i]
}
return obj
}
手写浅拷贝和深拷贝
最新推荐文章于 2024-07-15 14:30:35 发布