ECMAScript Object 的 Property 基本上是由 Key / Value 構成,連 Method 也是廣義 Property,我們該如何取得 Object 的所有 Key 呢 ?
Version
ECMAScript 2015
Object.keys()
Object Literal
let person = {
firstName: 'Sam',
lastName: 'Xiao',
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
Object.keys(person) // ?
以 object literal 定義 person
,在 object literal 的 property 都是 enumerable,所以 Object.keys()
都能顯示。
Object.keys()
顯示 Object 所有 enumerable property 的 key,但不包含 prototype 的 property
Object.create()
let person = Object.create({}, {
firstName: {
value: 'Sam',
writable: true,
configurable: true,
enumerable: true,
},
lastName: {
value: 'Xiao',
writable: true,
configurable: true,
enumerable: false,
},
fullName: {
value: function() {
return `${this.firstName} ${this.lastName}`
},
writable: true,
configurable: true,
enumerable: true,
},
})
Object.keys(person) // ?
若要特別建立 non enumerable property,就必須使用 Object.create()
,並特別設定是否為 enumerable。
第 8 行
lastName: {
value: 'Xiao',
writable: true,
configurable: true,
enumerable: false,
},
特別設定 lastName
property 的 enumerable
為 false
,則 Object.keys()
將無法顯示 lastName
。
Prototype
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Person.prototype.fullName = function() {
return `${this.firstName} ${this.lastName}`
}
let person = new Person('Sam', 'Xiao')
Object.keys(person) // ?
ECMAScript 的 OOP 正統寫法,是將 method 定義在 prototype,也因為定義在 prototype,Object.keys()
無法抓到該 method。
Class
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
fullName() {
return `${this.firstName} ${this.lastName}`
}
}
let person = new Person('Sam', 'Xiao')
Object.keys(person) // ?
若使用 ECMAScript 2015 的 class 寫法,Object.keys()
也只能抓到 firstName
與 lastName
,別忘了 class
本質仍是 constructor function,其 method 也是定義在 prototype,因此 Object.keys()
抓不到很合理。
Object.getOwnPropertyNames()
Object Literal
let person = {
firstName: 'Sam',
lastName: 'Xiao',
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
Object.getOwnPropertyNames(person) // ?
使用 Object.getOwnPropertyNames()
顯示 person
所有 property 的 key。
object.getOwnPropertyNames()
顯示 Object 所有 property 的 key,無論是 enumerable 或 non enumerable,但不包含 prototype 的 property
Object.create()
let person = Object.create({}, {
firstName: {
value: 'Sam',
writable: true,
configurable: true,
enumerable: true,
},
lastName: {
value: 'Xiao',
writable: true,
configurable: true,
enumerable: false,
},
fullName: {
value: function() {
return `${this.firstName} ${this.lastName}`
},
writable: true,
configurable: true,
enumerable: true,
},
})
Object.getOwnPropertyNames(person) // ?
僅管 lastName
的 Enumerable
為 false
,但 Object.getOwnPropertyNames()
仍然會顯示。
Prototype
let person = Object.create({
fullName: function() {
return `${this.firstName} ${this.lastName}`
}}, {
firstName: {
value: 'Sam',
writable: true,
configurable: true,
enumerable: true,
},
lastName: {
value: 'Xiao',
writable: true,
configurable: true,
enumerable: false,
},
})
Object.getOwnPropertyNames(person) // ?
將 fullName()
移到 prototype,而 object literal 都是 enumerable property。
但因為 Object.getOwnPropertyNames()
不會顯示 prototype 的 property,因此只能顯示 firstName
與 lastName
。
Class
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
fullName() {
return `${this.firstName} ${this.lastName}`
}
}
let person = new Person('Sam', 'Xiao')
Object.getOwnPropertyNames(person) // ?
若使用 ECMAScript 2015 的 class 寫法,Object.getOwnPropertyNames()
也只能抓到 firstName
與 lastName
,別忘了 class
本質仍是 constructor function,其 method 也是定義在 prototype,因此 Object.getOwnPropertyNames()
抓不到很合理。
for…in
Object Literal
let person = {
firstName: 'Sam',
lastName: 'Xiao',
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
for (let key in person)
console.log(key)
for...in
能顯示所有 enumerable,因此能顯示 object literal 所有 property 的 key。
for…in
如同Object.keys()
將 Object 所有 enumerable property 的 key 以 array 傳回,但包含 prototype 的 property
Object.create()
let person = Object.create({}, {
firstName: {
value: 'Sam',
writable: true,
configurable: true,
enumerable: true,
},
lastName: {
value: 'Xiao',
writable: true,
configurable: true,
enumerable: false,
},
fullName: {
value: function() {
return `${this.firstName} ${this.lastName}`
},
writable: true,
configurable: true,
enumerable: true,
},
})
for (let key in person)
console.log(key)
for...in
無法顯示 non enumerable property。
Prototype
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Person.prototype.fullName = function() {
return `${this.firstName} ${this.lastName}`
};
let person = new Person('Sam', 'Xiao')
for (let key in person)
console.log(key)
我們發現無論 Object.keys()
或 Object.getOwnPropertyNames()
,都無法顯示 prototype 的 property,但 for...in
可顯示。
Class
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
fullName() {
return `${this.firstName} ${this.lastName}`
}
}
let person = new Person('Sam', 'Xiao')
for (let key in person)
console.log(key)
但 for...in
搭配 ECMAScript 2015 的 class
時,卻不會顯示 fullName
。
理論上 class
的 fullName()
是在 prototype 上,for...in
應該會顯示卻沒顯示,也就是若搭配 class
,for...in
相當於 Object.keys()
,結果比較令人訝異。
Summary
Object.keys() | Object.getOwnPropertyNames() | for in | |
---|---|---|---|
Enumerable | Yes | Yes | Yes |
Non Enumerable | No | Yes | No |
Prototype | No | No | Yes |
Class | No Method | No Method | No Method |
Object.keys()
最中規中矩,不能顯示 non enumerable,也不能顯示 prototypeObject.getOwnPropertyNames()
有特異功能可顯示 non enumerable,但無法顯示 prototypefor in
有特異功能能顯示 Prototype,但無法顯示 non enumerable- 三種寫法都無法顯示 class 的 method
Conclusion
- 三種方式都各有其限制,要視需求選擇合適的方式
Object.keys()
與for..in
搭配class
時,竟然結果一樣,比較出乎意外
Reference
MDN, Object.keys()
MDN, Object.getOwnPropertyNames()
MDN, for in