Javascript 中常见的三种对象处理的方式
赋值、浅拷贝、深拷贝
深拷贝和浅拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
赋值和浅拷贝
**
赋值:
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝:
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
类型 | 是否指向同一对象 | 第一层为基本数据类型 | 第一层为引用数据类型 |
---|---|---|---|
赋值 | 是 | 改变会导致数据改变 | 改变会导致数据改变 |
浅拷贝 | 否 | 改变不会导致数据改变 | 改变会导致数据改变 |
深拷贝 | 否 | 改变不会导致数据改变 | 改变不会导致数据改变 |
简单的浅拷贝
Object.assign({},obj) 浅拷贝object
obj1={...obj2} 通过spread展开运算符浅拷贝obj2
Object.fromEntries(Object.entries(obj)) 通过生成迭代器再通过迭代器生成对象
Object.create({},Object.getOwnPropertyDescriptors(obj)) 浅拷贝obj
Object.defineProperties({},Object.getOwnPropertyDescriptors(obj)) 浅拷贝obj
深拷贝
//简单版深拷贝,只能拷贝基本原始类型和普通对象与数组,无法拷贝循环引用
function simpleDeepClone(a) {
const b=Array.isArray(a) ? [] : {}
for (const key of Object.keys(a)) {
const type = typeof a[key]
if (type !== 'object' || a[key] === null) {
b[key] = a[key]
} else {
b[key] = simpleDeepClone(a[key])
}
}
return b
}
//精简版深拷贝只能拷贝基本原始类型和普通对象与数组,可以拷贝循环引用
function deepClone(a, weakMap = new WeakMap()) {
if (typeof a !== 'object' || a === null) return a
if (s = weakMap.get(a)) return s
const b = Array.isArray(a) ? [] : {}
weakMap.set(a, b)
for (const key of Object.keys(a)) b[key] = clone(a[key], weakMap)
return b
}
//js原生深拷贝,无法拷贝Symbol、null、循环引用
function JSdeepClone(data) {
if (!data || !(data instanceof Object) || (typeof data == "function")) {
return data || undefined;
}
const constructor = data.constructor;
const result = new constructor();
for (const key in data) {
if (data.hasOwnProperty(key)) {
result[key] = deepClone(data[key]);
}
}
return result;
}
//深拷贝具体版,非完全,但大部分都可以
function deepClonePlus(a, weakMap = new WeakMap()) {
const type = typeof a
if (a === null || type !== 'object') return a
if (s = weakMap.get(a)) return s
const allKeys = Reflect.ownKeys(a)
const newObj = Array.isArray(a) ? [] : {}
weakMap.set(a, newObj)
for (const key of allKeys) {
const value = a[key]
const T = typeof value
if (value === null || T !== 'object') {
newObj[key] = value
continue
}
const objT = Object.prototype.toString.call(value)
if (objT === '[object Object]' || objT === '[object Array]') {
newObj[key] = deepClonePlus(value, weakMap)
continue
}
if (objT === '[object Set]' || objT === '[object Map]') {
if (objT === '[object Set]') {
newObj[key] = new Set()
value.forEach(v => newObj[key].add(deepClonePlus(v, weakMap)))
} else {
newObj[key] = new Map()
value.forEach((v, i) => newObj[key].set(i, deepClonePlus(v, weakMap)))
}
continue
}
if (objT === '[object Symbol]') {
newObj[key] = Object(Symbol.prototype.valueOf.call(value))
continue
}
newObj[key] = new a[key].constructor(value)
}
return newObj
}
—————————————————————————————————————————
引用:
部分引用并参考了原文 : https://juejin.im/post/6844904136161361933#heading-13
部分引用并参考了原文 : https://segmentfault.com/a/1190000018874254