總結下在JavaScript中遍歷對象的幾種方法。
for in
for in循環是最基礎的遍歷對象的方式,除了能拿到到對象自身的屬性之外,它還能拿到對象原型鏈上的屬性。
// 創建一個對象並指定其原型,yanggb為原型上的屬性 const obj = Object.create({ yanggb: 'yanggb' }) // yanggb1為對象自身的屬性 obj.yanggb1 = 'yanggb1' for (let key in obj) { console.log(obj[key]) // yanggb1, yanggb }
可以看到對象原型上的屬性也被循環出來了,首先是遍歷了自身的屬性,然后逐層往上遍歷原型鏈上原型的屬性。
如果想要過濾掉原型鏈上的屬性,也可以使用對象的hasOwnProperty()方法判斷其是否是自身屬性,以此來達到只針對自身的屬性做相應操作的目的。
for (let key in obj) { if (obj.hasOwnProperty(key)) { console.log(obj[key]) // yanggb1 } }
這時候原型上的yanggb屬性就被過濾掉了。
Object.keys
Object.keys()是ES5新增的一個對象方法,該方法返回對象自身屬性名組成的數組,它會自動過濾掉原型鏈上的屬性,然后可以通過數組的forEach()方法來遍歷。
Object.keys(obj).forEach((key) => { console.log(obj[key]) // yanggb1 })
此外還有Object.values()方法和Object.entries()方法,這兩方法的作用范圍和Object.keys()方法類似,分別是取得對象的屬性值數組和屬性鍵值數組數組。
for in循環和Object.keys()方法一樣,都不會返回對象的不可枚舉屬性,如果需要遍歷不可枚舉的屬性,就要使用Object.getOwnPropertyNames()方法了。
Object.getOwnPropertyNames
Object.getOwnPropertyNames()同樣也是ES5新增的一個對象方法,該方法會返回對象自身屬性名組成的數組,包括不可枚舉的屬性,因此也可以通過數組的forEach()方法來遍歷。
// 創建一個對象並指定其原型,yanggb為原型上的屬性 // yanggb1為對象自身的屬性並且不可枚舉 const obj = Object.create({ yanggb: 'yanggb' }, { yanggb1: { value: 'yanggb1', enumerable: false } }) obj.yanggb2 = 'yanggb2' // 不包括不可枚舉的yanggb1屬性 Object.keys(obj).forEach((key) => { console.log(obj[key]) // yanggb1 }) // 包括不可枚舉的yanggb1屬性 Object.getOwnPropertyNames(obj).forEach((key) => { console.log(obj[key]) // yanggb1,yanggb2 })
而在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('yanggb')]: { value: 'Symbol yanggb', enumerable: false } }) // 給對象添加一個可枚舉的Symbol屬性 obj[Symbol('yanggb1')] = 'Symbol yanggb1' Object.getOwnPropertySymbols(obj).forEach((key) => { console.log(obj[key]) // Symbol yanggb, Symbol yanggb1 })
這時候就會輸出所有的Symbol屬性,包括可枚舉不可枚舉Symbol屬性。
Reflect.ownKeys
Reflect.ownKeys()方法是ES2015新增的一個靜態方法,該方法返回對象自身所有屬性名組成的數組,包括不可枚舉的屬性和Symbol屬性。
Reflect.ownKeys(obj).forEach((key) => { console.log(obj[key]) // yanggb, yanggb1, Symbol yanggb, Symbol yanggb1 })
既然方法有那么多,自然需要對比一下才能知道不同的場景該怎么選用。
幾種方法的對比
通過一個表格直觀得對比:
方式 | 基本屬性 | 原型鏈 | 不可枚舉 | Symbol |
for in | 是 | 是 | 否 | 否 |
Object.keys() | 是 | 否 | 否 | 否 |
Object.getOwnPropertyNames() | 是 | 否 | 是 | 否 |
Object.getOwnPropertySymbols() | 否 | 否 | 是 | 是 |
Reflect.ownKeys() | 是 | 否 | 是 | 是 |
這其中只有for in循環會得到對象原型鏈上的屬性,其它方法都只適用於對象自身的屬性。
ES語言后續添加的新特性不會對以前的代碼產生副作用,比如在ES2015之前就存在的for in循環,Object.keys()和Object.getOwnPropertyNames()是肯定不會返回Symbol屬性的。
"成長的經歷,大概能讓人變得越來越安靜。"