// ECMA used the name Symbol.iterator. Symbols offer names that are unique and cannot clash // with other property names. Also, Symbol.iterator will return an object called an iterator. // This iterator will have a method called next which will return an object with keys value and done. const iterable = { [Symbol.iterator]() { let step = 0; const iterator = { next() { step++; if (step === 1) { return { value: 'This', done: false } } else if (step === 2) { return { value: 'is', done: false } } else if (step === 3) { return { value: 'iterable', done: true } } return { value: undefined, done: false }; } } return iterator } } // var iterator = iterable[Symbol.iterator](); // console.log(iterator.next()); // console.log(iterator.next()); // console.log(iterator.next()); // console.log(iterator.next()); // console.log(iterator.next()); const myFavouriteAuthors = { allAuthors: { fiction: [ 'Agatha Christie', 'J. K. Rowling', 'Dr. Seuss' ], scienceFiction: [ 'Neal Stephenson', 'Arthur Clarke', 'Isaac Asimov', 'Robert Heinlein' ], fantasy: [ 'J. R. R. Tolkien', 'J. K. Rowling', 'Terry Pratchett' ], }, [Symbol.iterator]() { const genres = Object.values(this.allAuthors); // console.log('genres', genres); let currentAuthorIndex = 0; let currentGenreIndex = 0; return { next() { const authors = genres[currentGenreIndex]; const doNothaveMoreAuthors = !(currentAuthorIndex < authors.length); if (doNothaveMoreAuthors) { currentGenreIndex++; currentAuthorIndex = 0; } const doNotHaveMoreGenres = !(currentGenreIndex < genres.length); if (doNotHaveMoreGenres) { return { value: undefined, done: true }; } return { value: genres[currentGenreIndex][currentAuthorIndex++], done: false } } }; } }; for (const author of myFavouriteAuthors) { console.log(author); } console.log(...myFavouriteAuthors)