js物件複製
物件是js裡重要的基本型別,廣義上講js裡萬物皆物件。複製一個資料,是一個常用的需求,但是相對於基本資料型別如數字,字串等,物件複製起來要複雜的多。
// 數字的複製
var m = 666
var n = m
console.log(n) // 666
複製程式碼
物件的複製是無法這樣的,以為這樣的複製只是複製了物件的引用
var o1 = {
m: 666,
n: 'abc'
}
var o2 = o1
console.log(o2.m) // 666
console.log(o2.n) // abc
// 改變o1會導致o2也發生改變
o1.m = 999
o1.n = 'def'
console.log(o2.m) // 999
console.log(o2.n) // def
複製程式碼
可以看出,當原物件發生改變,複製的物件也會發生改變,這不符合我們的要求。
下面我將介紹3種複製物件的方法:
- 使用遞迴遍歷物件的所有可列舉屬性然後複製
var copy_1 = function (obj) {
var o
// 檢測傳入資料的屬性,根據資料的型別分別處理
switch (typeof(obj)) {
case 'undefined':
break
case 'string':
o = obj + ''
break
case 'number':
o = obj - 0
break
case 'boolean':
o = !!obj
break
case 'object':
if (obj === null) {
o = null
} else {
if (Object.prototype.toString.call(obj).slice(8, -1) === 'Array') {
o = []
for (let v of obj) {
o.push(copy_1(v))
}
} else {
o = {}
// 遍歷物件,並遞迴遍歷物件每一層,然後複製每層屬性
for (let v in obj) {
o[v] = copy_1(obj[v])
}
}
}
break
default:
o = obj
}
return o
}
var o1 = {
m: 666,
n: 'abc'
}
var o2 = copy_1(o1)
o1.m = 123
console.log(o1.m) // 123
console.log(o2.m) // 666
複製程式碼
此方法不可複製物件的getter和setter屬性,不可列舉屬性
- 使用es6裡的Object.assign方法
var copy_2 = function (obj) {
var o
if (Object.prototype.toString.call(obj).slice(8, -1) === 'Array') {
o = []
} else {
o = {}
}
// 使用Object.assign()
return Object.assign(o, obj)
}
var o1 = {
m: 666,
n: 'abc'
}
var o2 = copy_2(o1)
o1.m = 123
console.log(o1.m) // 123
console.log(o2.m) // 666
複製程式碼
此方法不可複製物件的getter和setter屬性,不可列舉屬性,物件的繼承屬性
- 使用getOwnPropertyDescriptors和defineProperties
var copy_3 = function (obj) {
var o = {}
// 獲取原物件所有屬性的描述
var des = Object.getOwnPropertyDescriptors(obj)
// 通過物件屬性描述建立新物件
Object.defineProperties(o, des)
return o
}
var o1 = {
m: 666,
n: 'abc'
}
var o2 = copy_3(o1)
o1.m = 123
console.log(o1.m) // 123
console.log(o2.m) // 666
複製程式碼
此方法不可複製物件的繼承屬性
以上三種方法各有各的適用範圍,為了達到各種複製需求,可以考慮綜合幾種方法來達到複製的要求。