大清都亡了,你還用for...in...遍歷物件呢

weixin_34185560發表於2018-01-02

哈哈,標題黨一枚。這篇文章是介紹物件的列舉性和幾個用於遍歷物件方法的。主要是我讀《你不知道的js》時做的筆記,如有錯誤和疑惑請在評論區指出,檢視程式碼高亮優化版原文請點選連結,歡迎watch和star

列舉

不太瞭解物件的幾個屬性描述符的,請閱讀這篇文章

在上面這篇文章中,我們針對enumberable特性簡單說了什麼是可列舉性,我們可以針對物件的某個屬性設定其enumberable布林值來控制它的可列舉性。概括的說,可列舉就是可以出現在for...in..迴圈中,可以在物件屬性的遍歷中出現。

const obj={a:1,b:2}
Object.defineProperty(obj,'b',{
    enumerable:false
})
console.log('b' in obj) // true
for(let k in obj){
    console.log(k,obj[k]) // a 1
}

如上例,b確實是存在並且可訪問,但並不會出現在for...in...中。

正如標題所說,不要使用for...in...遍歷物件了,所以要是用另一種方式區分屬性是否可列舉:

const obj={a:1,b:2}
Object.defineProperty(obj,'b',{
    enumerable:false
})
console.log(obj.propertyIsEnumerable('b')) // false
console.log(Object.keys(obj)) // ['a']
console.log(Object.getOwnPropertyNames(obj)) ['a','b']

propertyIsEnumerable會檢查給定的屬性名是否存在於物件中(並非原型鏈上)並且可列舉。

我們也可以從上例中看出,Object.keysgetOwnPropertyNames兩者的區別。前者是返回可列舉的屬性,後者是返回所有的屬性。

遍歷

1.for...in...

它可以遍歷物件的可列舉屬性列表,包括原型鏈。使用它遍歷物件是無法直接獲取屬性值的,需要手動繫結物件屬性指向值。

2.for...of...

ES6中增加了一種遍歷陣列的語法,他是直接遍歷值,而不是陣列下標,當然如果物件本身定義了迭代器也可以遍歷物件。

const arr=[1,2,3]
for(let v of arr){
    console.log(v)
}
// 1
// 2
// 3

和陣列不同,普通的物件沒有內建的迭代器,所以無法通過```for...of...遍歷。我們可以給項便利的物件定義 @@iterator`(迭代器)。

const obj={a:1,b:2}
Object.defineProperty(obj,Symbol.iterator,{ 
    value(){
        const o=this
        let idx=0
        const keys=Object.keys(o)
        return {
            next(){
                return {
                    value:o[keys[idx++]],
                    done:(idx>keys.length)
                }
            }
        }
    }
})

也可以直接在定義物件時進行宣告:

const obj={a:1,b:2,[Symbol.iterator](){
    const o=this
        let idx=0
        const keys=Object.keys(o)
        return {
            next(){
                return {
                    value:o[keys[idx++]],
                    done:(idx>keys.length)
                }
            }
        }
}}

我們來手動遍歷物件:

const it=obj[Symbol.iterator]()
console.log(it.next()) // {value: 1, done: false}
console.log(it.next()) // {value: 2, done: false}
console.log(it.next()) // {value: undefined, done: true}

使用for...of...遍歷

for(let v of obj){
    console.log(v)
}
// 1
// 2

3.Object.keys

如果是使用過airbnb的eslint規範的人都知道,使用for...in...遍歷物件屬性會報語法錯誤。我們通常的解決方法就是用Object.keys得到包含可列舉的屬性名陣列,再使用forEach進行遍歷。

const obj={a:1,b:2}
const keys=Object.keys(obj)
keys.forEach(key=>{console.log(obj[key])})
// 1
// 2

相關文章