photo by Tine Ivanič on unsplash
If you cannot explain what you are attempting to accomplish to a sixyear-old child, then you are probably not clear about it yourself. -Albert Einstein
Javascript裡的for迴圈家族,不外乎就是for、forEach、for…in以及for…of,這幾個兄弟了,而今天我們要針對for…in和for…of做深入的介紹。
for in這個語法是在ES5就已經出現的語法,而他可以針對物件(Object)以及陣列(Array)做遍歷,來看看以下的程式碼範例。
首先在物件的範例中,我們有一個名為Jason的物件,接著我們透過自定義的prop,存取物件裡的屬性(property),而for in迴圈會遍歷物件裡所有的屬性,直到所有屬性都遍歷完成,所以在這個範例,他會遍歷兩次,把firstName和lastName都console出來;在陣列的範例中,for in迴圈則會把陣列裡的所有元素(element)的索引值(index)給遍歷出來。
接著我們在剛剛的物件和陣列增加一個屬性foo,value帶上bar,迴圈依然正常的輸出。
而如果我們是透過函式建構式(function constructor)來創造物件時,物件可能會繼承含是建構式的一些屬性和方法,這時如果直接用for in迴圈時,繼承的屬性和方法也會一起被輸出。
可以發現在prototype裡繼承的方法也被輸出了。
為了避免此問題,網路上有一種通用解法,使用Object.prototype.hasOwnProperty,透過這個方法可以檢查這個屬性是否是直接或是繼承的,他會回傳一個布林值,當是true的時候,表該屬性是直接的。
當然還有一種方法,就是用Object.keys(),但是他會回傳一個陣列,裡面的元素這個物件會回傳一個陣列,裡面的元素會是這個物件裡的所有屬性,且不包含繼承的屬性;同樣的,如果你要取物件裡所有的值,也可以使用Object.values(),這個方法會回傳一個陣列,裡面的元素會是這個物件裡的所有值,且也不包含繼承下來的值。
同樣的,陣列在使用for in迴圈時,也有上述會把繼承的方法或屬性輸出的情況。
為了避免此問題發生,我們可以直接用一般的for迴圈就可以了。不過我們也可以直接用for of迴圈和Object.entries(),for of迴圈稍後會再詳細介紹一下。
所以根據以上for in奇怪的部分,我們在處理有繼承屬性的物件或陣列時,應該避免去使用for in迴圈,以防產生預期之外的狀況。取而代之的是,你可以好好利用Object.keys()、Object.values()、Object.entries()結合一般的for迴圈處理物件;至於陣列的處理,就輪到我們接下來要講的for of迴圈。
終於,ES6裡面出現了for of迴圈的語法,它主要彌補了for迴圈家族的不足處,你可以利用它來處理迭代(iterable)的資料,像是陣列、字串、set、map、型別陣列等等。
看以下範例:
剛剛也說到for of補足了以往for迴圈家族的一些缺點,例如:forEach無法使用continue、break、return等等語句,但for of可以支持;for of也解決上面所講的繼承問題;for of的語法也比一般for迴圈寫法更加簡潔。而且最棒的是他支援相當多的迭代類型資料。
所以當你以後遇到要處理迭代資料且需要用到迴圈時,不妨可以試試for of迴圈。