幾天前一個小夥伴問我 Object.getOwnPropertyNames()
是幹什麼用的
平時還真沒有使用到這個方法,一時不知如何回答
從方法名稱來分析,應該是返回的是物件自身屬性名組成的陣列
那和 Object.keys()
方法不就一樣了嗎
感覺事情並不這麼簡單,於是我仔細看了一下這幾種遍歷物件的方法的區別
for in
for in 迴圈是最基礎的遍歷物件的方式,它還會得到物件原型鏈上的屬性
// 建立一個物件並指定其原型,bar 為原型上的屬性
const obj = Object.create({
bar: 'bar'
})
// foo 為物件自身的屬性
obj.foo = 'foo'
for (let key in obj) {
console.log(obj[key]) // foo, bar
}
可以看到物件原型上的屬性也被迴圈出來了
在這種情況下可以使用物件的 hasOwnProperty()
方法過濾掉原型鏈上的屬性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(obj[key]) // foo
}
}
這時候原型上的 bar 屬性就被過濾掉了
Object.keys
Object.keys()
是 ES5 新增的一個物件方法,該方法返回物件自身屬性名組成的陣列,它會自動過濾掉原型鏈上的屬性,然後可以通過陣列的 forEach()
方法來遍歷
Object.keys(obj).forEach((key) => {
console.log(obj[key]) // foo
})
另外還有 Object.values()
方法和 Object.entries()
方法,這兩方法的作用範圍和 Object.keys()
方法類似,因此不再說明
for in 迴圈和 Object.keys()
方法都不會返回物件的不可列舉屬性
如果需要遍歷不可列舉的屬性,就要用到前面提到的 Object.getOwnPropertyNames()
方法了
Object.getOwnPropertyNames
Object.getOwnPropertyNames()
也是 ES5 新增的一個物件方法,該方法返回物件自身屬性名組成的陣列,包括不可列舉的屬性,也可以通過陣列的 forEach
方法來遍歷
// 建立一個物件並指定其原型,bar 為原型上的屬性
// baz 為物件自身的屬性並且不可列舉
const obj = Object.create({
bar: 'bar'
}, {
baz: {
value: 'baz',
enumerable: false
}
})
obj.foo = 'foo'
// 不包括不可列舉的 baz 屬性
Object.keys(obj).forEach((key) => {
console.log(obj[key]) // foo
})
// 包括不可列舉的 baz 屬性
Object.getOwnPropertyNames(obj).forEach((key) => {
console.log(obj[key]) // baz, foo
})
ES2015 新增了 Symbol 資料型別,該型別可以作為物件的鍵,針對該型別 ES2015 同樣新增了 Object.getOwnPropertySymbols()
方法
Object.getOwnPropertySymbols
Object.getOwnPropertySymbols()
方法返回物件自身的 Symbol 屬性組成的陣列,不包括字串屬性
Object.getOwnPropertySymbols(obj).forEach((key) => {
console.log(obj[key])
})
什麼都沒有,因為該物件還沒有 Symbol 屬性
// 給物件新增一個不可列舉的 Symbol 屬性
Object.defineProperties(obj, {
[Symbol('baz')]: {
value: 'Symbol baz',
enumerable: false
}
})
// 給物件新增一個可列舉的 Symbol 屬性
obj[Symbol('foo')] = 'Symbol foo'
Object.getOwnPropertySymbols(obj).forEach((key) => {
console.log(obj[key]) // Symbol baz, Symbol foo
})
Reflect.ownKeys
Reflect.ownKeys()
方法是 ES2015 新增的靜態方法,該方法返回物件自身所有屬性名組成的陣列,包括不可列舉的屬性和 Symbol 屬性
Reflect.ownKeys(obj).forEach((key) => {
console.log(obj[key]) // baz, foo, Symbol baz, Symbol foo
})
對比
方式 | 基本屬性 | 原型鏈 | 不可列舉 | Symbol |
---|---|---|---|---|
for in | 是 | 是 | 否 | 否 |
Object.keys() | 是 | 否 | 否 | 否 |
Object.getOwnPropertyNames() | 是 | 否 | 是 | 否 |
Object.getOwnPropertySymbols() | 否 | 否 | 是 | 是 |
Reflect.ownKeys() | 是 | 否 | 是 | 是 |
結論
這其中只有 for in 迴圈會得到物件原型鏈上的屬性,其它方法都只適用於物件自身的屬性
ES 語言後續新增的新特性不會對以前的程式碼產生副作用,比如在 ES2015 之前就存在的 for in 迴圈,Object.keys() 和 Object.getOwnPropertyNames() 是肯定不會返回 Symbol 屬性的