js深拷贝是我们写代码时碰到的比较多的情况,就是将一个引用类型以及它下面的所有引用类型提出,改变新的而不影响旧的。
我总结了以下几种方式以及要点:
1.JSON序列化
这是我们比较常用的一种方式,但其实它有些缺点,先上代码
1.1对js原生对象的测试
let deepClone = function (obj) {
return JSON.parse(JSON.stringify(obj))
}
let a = {
name: "lily",
age: 20,
hobbit: ["dance", "sing", {
type: "sports",
value: "run"
}],
schoolData: {
grades: "A"
},
run:function(){
},
walk:undefined,
fly:NaN
}
let b = deepClone(a);
console.log(b)
// {
// name: 'lily',
// age: 20,
// hobbit: [ 'dance', 'sing', { type: 'sports', value: 'run' } ],
// schoolData: { grades: 'A' },
// fly: null
// }
console.log(b === a) //false
对比我们原先创建的对象和新对象,我们发现:
1.不会拷贝对象上的value值为undefined和函数的键值对
2.nan,无穷大,无穷小会转为null
2.2自定义对象测试
let Father = function(){
this.name = "Father"
}
Father.prototype.walk = function(){
console.log("walk")
}
let Son = function(){
//构造函数继承应该写在函数首部,避免对子函数定义属性的冲突
Father.call(this,arguments)
this.name = "Son"
}
let tempFunc = function(){}
tempFunc.prototype = Father.prototype
Son.prototype = new tempFunc()
Son.prototype.age = 18
Son.prototype.run = function(){
console.log("run")
}
Object.defineProperty(Son.prototype,"constructor",{
value:Son,
enumerable:false
})
let son = new Son()
let copySon = JSON.parse(JSON.stringify(son))
// console.log(copySon.constructor) //[Function: Object]
// console.log(copySon.age) //undefined
// console.log(copySon.run()) //TypeError: copySon.run is not a function
// console.log(copySon.walk()) //TypeError: copySon.walk is not a function
// console.log(copySon.toString()) //[object Object]
可见:
1.将constructor强行转为Object
2.无法获取自己原型链上的内容,只能获取Object原型内容
值得提的是:date对象经过序列化会变成date字符串
总结:由于拷贝函数本身没有什么用处(不能改变函数内部代码,顶多给函数加点私有属性),
若不在乎
1.取不到值为undefined的键
2.NaN和无穷转变为null
3.原型内容
4.date对象转为date字符串
则可以使用JSON序列化进行深拷贝
若不想用JSON序列化的方式,可以参考我写的深拷贝函数https://www.jianshu.com/p/a67b7fbe629b