對象是js裏重要的基本類型,廣義上講js裏萬物皆對象。複製一個數據,是一個經常使用的需求,可是相對於基本數據類型如數字,字符串等,對象複製起來要複雜的多。javascript
// 數字的複製
var m = 666
var n = m
console.log(n) // 666
複製代碼
對象的複製是沒法這樣的,覺得這樣的複製只是複製了對象的引用java
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
複製代碼
能夠看出,當原對象發生改變,複製的對象也會發生改變,這不符合咱們的要求。es6
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屬性,不可枚舉屬性ui
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屬性,不可枚舉屬性,對象的繼承屬性spa
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
複製代碼
此方法不可複製對象的繼承屬性prototype
以上三種方法各有各的適用範圍,爲了達到各類複製需求,能夠考慮綜合幾種方法來達到複製的要求。code