Javascript 中常见的三种对象处理的方式
赋值、浅拷贝、深拷贝
深拷贝和浅拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
赋值和浅拷贝
**
赋值:
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝:
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
| 类型 | 是否指向同一对象 | 第一层为基本数据类型 | 第一层为引用数据类型 |
|---|---|---|---|
| 赋值 | 是 | 改变会导致数据改变 | 改变会导致数据改变 |
| 浅拷贝 | 否 | 改变不会导致数据改变 | 改变会导致数据改变 |
| 深拷贝 | 否 | 改变不会导致数据改变 | 改变不会导致数据改变 |
简单的浅拷贝
Object.assign({},obj) 浅拷贝objectobj1={...obj2} 通过spread展开运算符浅拷贝obj2Object.fromEntries(Object.entries(obj)) 通过生成迭代器再通过迭代器生成对象Object.create({},Object.getOwnPropertyDescriptors(obj)) 浅拷贝objObject.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 aif (s = weakMap.get(a)) return sconst 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 aif (a === null || type !== 'object') return aif (s = weakMap.get(a)) return sconst 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 valueif (value === null || T !== 'object') {newObj[key] = valuecontinue}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
