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
對比我們原先創(chuàng)建的對象和新對象,我們發(fā)現(xiàn):
1.不會拷貝對象上的value值為undefined和函數(shù)的鍵值對
2.nan,無窮大,無窮小會轉為null
2.2自定義對象測試
let Father = function(){
this.name = "Father"
}
Father.prototype.walk = function(){
console.log("walk")
}
let Son = function(){
//構造函數(shù)繼承應該寫在函數(shù)首部,避免對子函數(shù)定義屬性的沖突
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字符串
總結:由于拷貝函數(shù)本身沒有什么用處(不能改變函數(shù)內部代碼,頂多給函數(shù)加點私有屬性),
若不在乎
1.取不到值為undefined的鍵
2.NaN和無窮轉變?yōu)閚ull
3.原型內容
4.date對象轉為date字符串
則可以使用JSON序列化進行深拷貝
若不想用JSON序列化的方式,可以參考我寫的深拷貝函數(shù)http://www.itdecent.cn/p/a67b7fbe629b