概念
首先来区分几个概念:赋值,浅拷贝和深拷贝
赋值
对于基本类型,就是直接把值 赋给变量, 对于引用类型就是把引用地址赋给变量
let obj = {x: 1}
let obj1 = obj
console.log(obj === obj1) // true
浅拷贝
浅拷贝是对于引用类型来说的, 如果对象里的属性值是基本类型, 浅拷贝就是复制该属性值的值, 对于属性值是引用类型的, 就复制该值的引用地址,常见的浅拷贝:
let obj = {x: 1, y: {c: 666}}
let obj1 = {...obj}
console.log(obj === obj1) // false
console.log(obj.y === obj1.y) // true
深拷贝
深拷贝是直接开辟一个空间存放要拷贝的对象,两个对象对应不同应用地址 常用乞丐版深拷贝:
let obj = {x: 1, y: {c: 999}}
let obj1 = JSON.parse(JSON.stringify(obj))
console.log(obj === obj1) // false
console.log(obj.y === obj1.y) // false
但是这样的深拷只能拷贝对象和数组,对于函数,undefined,null,symbol之类的会有问题, 而且还有所拷贝的对象中不能有循环引用, 否则会报错。
实现深浅拷贝
// 测试用例
let obj = {
0: 'math',
1: 'chinese',
2: 'elglish',
score: {
math: 98,
chinese: 100,
elglish: 19,
},
reg: /\d+/img,
time: new Date,
friends: ['tom', 'jerry'],
say: function () {
console.log('good good study!');
},
tag: Symbol('TAG'),
[Symbol.toStringTag]: 'object'
};
// 获取对象类型
function getType(obj) {
return Object.toString.call(obj).slice(8, -1)
}
浅拷贝
function shallowCopy (obj) {
let Ctor = obj.constructor
let type = getType(obj)
// 1. 对于symbol和bigInt
if(/^(symbol|bigint)&/i.test(type)) return Object(obj)
// 2. 对于是error
if(/^error$/i.test(type)) return new Ctor(obj.message)
// 3. regexp/ date
if(/^(regexp|date)$/i.test(type)) return new Ctor(obj)
// 4. function // 返回新函数:新函数执行还是把原始函数执行,实现和原始函数相同的效果
if(/^function$/i.test(type)) {
return function () {
return obj.call(this, ...arguments)
}
}
// 5. object and array
if(/^(object|array)$/i.test(type)){
// 获取键
let keys = [
...Object.keys(obj),
...Object.getOwnPropertySymbols(obj)
]
let newObj = new Ctor()
for(let key of keys) {
newObj[key] = obj[key]
}
return newObj
}
return obj
}
深拷贝
function deepCopy (obj, set = new Set()) {
let Ctor = obj.constructor
let type = getType(obj)
if(!/^(array|object)$/i.test(type)) return shallowCopy(obj)
if(set.has(obj)) return obj // 防止循环引用
set.add(obj)
let keys = [
...Object.keys(obj),
...Object.getOwnPropertySymbols(obj)
]
let result = new Ctor()
for(let key of keys){
result[key] = deepCopy(obj[key], set)
}
return result
}
测试
let obj1 = shallowCopy(obj)
let obj2 = deepCopy(obj)
console.log(obj === obj1) // false
console.log(obj === obj2) // false
console.log(obj.score === obj1.score) // true
console.log(obj.score === obj2.score) // false
obj.friends.push('shetia')
console.log(obj1, '---------------obj1')
console.log(obj2, '---------------obj2')