for...of為啥不遍歷Object對象

我們講了簡單又實用的for...of,我們可以使用它來遍曆數組,字元串,Set和Map結構,但是有沒有發現,我們並沒有說它可以遍歷Object對象,為什麼不試試用它來遍歷Object對象呢?

oh no,程序報錯了,for...of根本不支持遍歷普通的Object對象,還出現了錯誤提示:obj[Symbol.iterator]不是一個function,這是什麼鬼?

為什麼數組,Set和Map結構又可以支持for...of的遍歷呢?

原來,要想能夠被for...of正常遍歷的,都需要實現一個遍歷器Iterator。而數組,Set和Map結構,早就內置好了遍歷器Iterator(又叫迭代器),它們的原型中都有一個Symbol.iterator方法;而Object對象並沒有實現這個介面,使得它無法被for...of遍歷。

那麼,我們就親自來驗證一下,它們的原型中到底是不是有個叫Symbol.iterator的方法:

從上往下看,確實,唯獨Object對象的原型上沒有Symbol.iterator,返回了:undefined。其他的數據類型的原型上都含有一個名字叫Symbol.iterator的方法Function。

注意:Symbol.iterator 是Symbol 對象的 iterator 屬性,是一個特殊的Symbol值,因此,當它作為prototype對象屬性名的時候,獲取它的時候需要使用[ ]的形式: prototype[Symbol.iterator],不能使用點形式獲取:prototype.Symbol.iterator。原因是點形式會把後面的值當作是字元串類型處理,而不是Symbol類型。第十一節有介紹,點擊查看。

也就說,只要一個數據結構擁有一個叫[Symbol.iterator]()方法的數據結構,就可以被for...of遍歷,我們稱之為:可遍歷對象。比如:數組,字元串,Set和Map結構。

現在你該知道為什麼文章第一個案例會出現錯誤提示:obj[Symbol.iterator]不是一個function 了吧,因為Object對象的原型上壓根就沒有[Symbol.iterator]() 方法啊。

既然我們知道擁有[Symbol.iterator]()方法就可以被遍歷,我們就會好奇:[Symbol.iterator]方法到底做了什麼這麼牛逼,它的原理是什麼?

Iterator遍歷器的原理

當可遍歷對象被for...of遍歷的時候,[Symbol.iterator]()就會被調用,返回一個iterator對象。其中還有一個很重要的方法:next( );

第1次調用next( )方法:返回數組的第1個元素:「a」,以及done的值為fasle,表示循環沒有結束,繼續遍歷。

第2次調用next( )方法:返回數組的第2個元素:「b」,以及done的值還是為fasle,表示循環沒有結束,繼續遍歷。

第3次調用next( )方法:返回數組的第3個元素:「c」,以及done的值依然為fasle,表示循環沒有結束,繼續遍歷。

第4次調用next( )方法:返回的value值為undefined,以及done的值變成了true,表示遍歷結束。

原來,for...of的原理就是:先調用可遍歷對象的[Symbol.iterator]( )方法,得到一個iterator遍歷器對象,然後就在遍歷器上不斷調用next( )方法,直到done的值為true的時候,就表示遍歷完成結束了

自定義Iterator遍歷器

既然有了[Symbol.iterator]()方法就算是可遍歷對象,那麼我給Object對象手動加上一個[Symbol.iterator]()方法,那麼它是不是可以被for...of遍歷了?

那我們就試試看,給一個Object對象加一個[Symbol.iterator]( )方法,看它是不是就能被for...of遍歷了?

上面這個案例也許你看了覺得很複雜,沒看懂,沒關係,我一起來分析它的結構就夠了!

我們定義了一個Object對象,同時給它添加了[Symbol.iterator]()方法,並在[Symbol.iterator]()方法實現了next( )方法,next( )方法返回的對象包含了value屬性和done屬性。

具體細節如果不理解沒關係,我們確實看到了給Object對象加上了[Symbol.iterator]()方法後,最後確實能被for...of遍歷了。

這就是說,我們可以創建一個可遍歷的對象,並且自定義它的遍歷行為。或者說可以通過添加[Symbol.iterator]()方法,把一個不可遍歷的Object對象,變成可遍歷的對象。

Iterator遍歷器的價值

新特性for...of之所以能夠遍歷各種不同的數據結構,正是因為這個數據結構都實現了Iterator遍歷器介面,供for...of遍歷。如果沒有實現Iterator介面,則該數據結構無法被for...of遍歷,比如:普通的Object對象。

總結:Iterator遍歷器為各種數據結構提供一個統一的遍歷介面,使得for...of能夠輕鬆簡便地訪問數據成員。 數據結構實現了Iterator介面,我們稱之為可遍歷對象。我們也可以自己創建可遍歷對象並自定義遍歷行為。


推薦閱讀:
查看原文 >>
相关文章