深浅拷贝
let obj = {
name: 'Tom',
age: 20,
msg: {
job: 'coder',
},
arr: [1,2,3],
fn: function(value) {
return value;
},
};
浅拷贝
方式一
const newObj1 = {}
for (let k in obj) {
newObj1[k] = obj[k]
}
console.log('方式一',newObj1,newObj1 === obj)
方式二
1、不会拷贝对象的继承属性
2、不会拷贝对象的不可枚举属性
3、可以拷贝symbol类型的属性
const newObj2 = {}
Object.assign(newObj2, obj)
console.log('方式二',newObj2,newObj2 === obj)
方式三
const newObj3 = { ...obj }
console.log('方式三', newObj3, newObj3 === obj)
深拷贝
方式一:乞丐版(JSON.stringfy)
-
拷贝的对象值中如果有函数、undefiend、symbol这几种类型,经过JSON.stringfy序列化之后的字符串中这个键值对会消失
-
拷贝Date引用类型会变成字符串
-
无法拷贝不可枚举类型
-
无法拷贝对象的原型链
-
拷贝RegExp引用类型会变成空对象
-
对象中含有NaN、infinity、以及-infinity、JSON序列化的结果会变成null
-
无法拷贝对象的循环引用,即对象成环(obj[key] = obj)
方式二:基础版(手写递归实现)
- 下列函数并不难复制不可枚举的属性以及Symbol类型
- 这种只是针对普通的引用类型的值做递归复制
- 对象的属性里面成环,即虚幻引用没有解决
RangeError: Maximum call stack size exceeded
function deepClone(target) {
let newObj = target instanceof Array ? [] : {}
for (let k in target) {
if (typeof *target*[k] !== 'object') newObj[k] = *target*[k]
else newObj[k] = deepClone(*target*[k])
}
return newObj
}
const deepObj = deepClone(obj)
console.log('deepObj',deepObj)
方式三:深拷贝的改进版
- 针对能够遍历对象的不可枚举属性以及Symbol类型.,使用
Reflect.ownKeys方法 - 利用Object的
getOwnPropertyDescriptors方法可以获得对象的所有属性,以及对应的特性,再结婚Object的create方法创建一个新对象.,并继承传入原对象的原型链 - 利用
WeakMap类型作为hash表,因为WeakMap是弱引用类型,可以有效防止内存泄露,作为检测循环引用很有帮助,如果存在循环,则直接返回WeakMap存储的值
const isComolexDataType = obj => (
typeof obj === 'object' || typeof obj === 'function'
) && (obj !== null)
const deepClone = function(obj, hash = new WeakMap()) {
if (obj.constructor === Date) return new Date(obj) //日期对象直接返回一个新的日期对象
if (obj.constructor === RegExp) return new RegExp(obj) // 正则对象直接返回一个新的正则对象
//若是循环引用就用 weakMap 来解决
if (hash.has(obj)) return hash.get(obj)
let allDesc = Object.getOwnPropertyDescriptors(obj)
// 遍历传入参数所有键的特性
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
//继承原型链
hash.set(obj, cloneObj)
for (let key of Reflect.ownKeys(obj)) {
cloneObj[key] = (isComolexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key],hash) : obj[key]
}
return cloneObj
}
//测试代码
let testObj = {
name: 'Tom',
age: 22,
boolean: true,
unf: undefined,
nu: null,
obj: {
name: 'Jakc',
age:10000
},
arr: [1, 2, '34', { name: 'Herry' }],
fn: function() {
console.log('我是函数')
},
date: new Date(0),
reg: new RegExp('/我是正则/ig'),
[Symbol('1')]:1
}
Object.defineProperty(testObj, 'innumerable', {
enumerable: false,
value:'不可枚举属性'
})
testObj = Object.create(testObj, Object.getOwnPropertyDescriptors(testObj))
// 设置loop成循环引用的属性
testObj.loop = testObj
const testobj1 = deepClone(testObj)
testObj.arr.push(4873289)
console.log('完善', testobj1 === testObj);
console.log('testobj:',testObj)
console.log('testobj1',testobj1)