前端深拷贝实现
前端深拷贝实现
1. JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj))
实现深拷贝的过程是利用JSON.stringify()
将对象序列化(转换成一个JSON字符串),再使用JSON.parse()
进行反序列化(还原)。
弊端
如果 obj 里有时间对象,则JSON.parse(JSON.stringify(obj))
的结果将只是字符串,而不是时间对象:
const date = new Date();
const newDate = JSON.parse(JSON.stringify(date));
console.log(typeof newDate); // string
如果 obj 里有 RegExp、Error 对象
,则序列化的结果将只会得到空对象:
const reg = new RegExp();
const err = new Error();
const newReg = JSON.parse(JSON.stringify(reg));
const newErr = JSON.parse(JSON.stringify(err));
console.log(newReg); // {}
console.log(newErr); // {}
如果 obj 里有函数、undefined,则序列化的结果会将函数、undefined 丢失:
const object = {
fn: () => {},
x: undefined,
}
const newObject = JSON.parse(JSON.stringify(object));
console.log(newObject); // {}
如果 obj 里有 NaN、Infinity、-Infinity
,则序列化的结果会得到null
:
const object = {
x: NaN,
y: Infinity,
z: -Infinity,
}
const newObject = JSON.parse(JSON.stringify(object));
console.log(newObject); // {x: null, y: null, z: null}
JSON.stringify()
只能序列化对象的可枚举的自有属性,如果 obj 中有对象是构造函数生成的,则使用JSON.parse(JSON.stringify(obj))
深拷贝后,会丢失对象的 constructor:
function Person(name, age) {
this.name = name;
this.age = age;
}
const dlrb = new Person('迪丽热巴', 18);
const object = {
x: dlrb
}
const newObject = JSON.parse(JSON.stringify(object));
console.log(newObject.x.__proto__.constructor === Person); // fasle
如果 obj 中存在循环引用,会陷入死循环:
const object = {
x: 1,
}
object.object = object;
const newObject = JSON.parse(JSON.stringify(object)); // error
排除以上情况,可以使用JSON.parse(JSON.stringify(obj))
来实现深拷贝。
2. 封装deepClone函数
function deepClone(target){
if(target !== null && typeof target === 'object'){
let result = Object.prototype.toString.call(target) === "[object Array]" ? [] : {};
for (let k in target){
if (target.hasOwnProperty(k)) {
result[k] = deepClone(target[k])
}
}
return result;
}else{
return target;
}
}
以上代码中,deepClone
函数的参数 target
是要深拷贝的数据。
执行 target !== null && typeof target === 'object'
判断 target
是不是引用类型。
若不是,直接返回 target
。
若是,判断引用类型的数据是对象类型还是数组类型,然后创建一个变量 result
作为深拷贝的结果,遍历 target
,执行 deepClone(target[k])
把 target
每个属性的值深拷贝后赋值到深拷贝的结果对应的属性 result[k]
上,遍历完毕后返回 result
。
在执行 deepClone(target[k])
中,又会对 target[k]
进行类型判断,重复上述流程,形成了一个递归调用 deepClone
函数的过程。就可以层层遍历要拷贝的数据,不管要拷贝的数据有多少子属性,只要子属性的值的类型是引用类型,就会调用 deepClone
函数将其深拷贝后赋值到深拷贝的结果对应的属性上。
另外使用 for...in
循环遍历对象的属性时,其原型链上的所有属性都将被访问,如果只要只遍历对象自身的属性,而不遍历继承于原型链上的属性,要使用 hasOwnProperty
方法过滤一下。
- 0
- 0
- 0
- 0
- 0
- 0