提供給for..of的物件必須有可迭代性(iterable)
而物件(Object)不可迭代,僅能用特殊方法獲取可枚舉(enumerable)的屬性值
這時候可以在 Object 上增加一個特殊的屬性 [Symbol.iterator]
來讓 Object 可以被迭代
呼叫這個方法應回傳一個物件,用以提供第二個 interface ,也就是迭代器(iterator)
迭代器附有一個 next method,具有 value 跟 done 屬性
若下一個值存在,則具有 value 且 done 為 false
若沒有下個值,則不具有 value 且 done 為 true
示例如下
const myDiet = {
meal: {
breakfast: "apple",
lunch: "avocado",
dinner: ["cabbage", "carrot"],
},
haveMeal: function (foodName, mealName) {
console.log(`I have ${foodName} as ${mealName}.`);
},
[Symbol.iterator]() {
const nameOfMeal = Object.keys(this.meal);
const nameOfFood = Object.values(this.meal);
let index = 0;
// must return an iterator object with a `next()` method
return {
next: () => {
if (index < nameOfFood.length) {
this.haveMeal(nameOfFood[index], nameOfMeal[index]);
return { value: nameOfFood[index++], done: false };
} else {
return { done: true };
}
},
};
},
};
for (const item of myDiet) {
console.log(item);
}
[Symbol.iterator] 並不是要用來『取代』其他物件方法
當物件屬性混合了不同資料類型的話,可用 [Symbol.iterator] 來建立出乾淨且清晰的自訂迭代內部值的方法,它允許為複雜物件建立簡單且標準的迭代,向迴圈隱藏物件的內部結構
以上方例子來說,執行for loop時並不會知道 myDiet 物件 meal 屬性的內部結構,這有助於抽象化(Abstraction)與封裝(Encapsulation)