Symbol
ES6 introcues a new type called symbol. The Symbol function returns a value of type symbol.
const symbol1 = Symbol();
const symbol2 = Symbol('hi');
console.log(typeof symbol1); //symbol
console.log(symbol3.toString()); //Symbol(foo)
// each symbol value created by Symbol function is unique
console.log(Symbol('foo') === Symbol('foo')); // false
// Symbol itself is a function
console.log(typeof Symbol); //function
Iterator
An iterator is an object that provides a next method which returns the next item in the sequence. This method returns an object with two properties: done and value. For an object to be iterable, it must have a function property with a Symbol.iterator key, which returns a new iterator for each call.
// Array has build-in iteration support
functioin forOf(arr) {
for(let i of arr) {
console.log(i);
}
}
/**
* for...of loops is based on iterator
* so forOf implementation above is basically:
*/
function iterating(arr) {
let iterator = arr[Symbol.iterator](); //get the iterator for the array
let next = iterator.next();
while(!next.done) {
console.log(next.value);
next = iterator.next();
}
}
Make Object iterable
Object doesn't have build-in iteration support.
let obj = {a: 'b', c: 'd'}
for(let i of obj) {
//Uncaught TypeError: obj is not iterable
console.log(i);
}
To make Object iterable, we have to add Symbol.iterator, either to the instance or the prototype.
Object.defineProperty(Object.prototype, Symbol.iterator, {
value: function() {
let keys = Object.keys(this);
let index = 0;
return {
next: () => {
let key = keys[index++];
return {
value: `${key}-${this[key]}`,
done: index > keys.length
}
}
};
},
enumerable: false
});
let obj = {a: 'b', c: 'd'}
for(let i of obj) {
console.log(i); // a-b c-d
}
Generator
The function declaration defines a generator function, whose return value is generator object. The generator object conforms to the iterator protocol. Note generator function* itself is a function.
//generator function
function* generatorFn() {
yield 1;
return 2;
}
// generator object - iterator
let generatorObj = generatorFn();
let nextItem = generatorObj.next();
console.log(typeof generatorFn); //function
console.log(typeof generatorObj); //object
console.log(typeof generatorObj.next); //function
console.log(nextItem); //{value: 1, done: false}
Therefore, to make Object iterable, we can define its Symbol.iterator with generator function.
Object.defineProperty(Object.prototype, Symbol.iterator, {
value: function*() {
let keys = Object.keys(this);
for(let key of keys) {
yield `${key}-${this[key]}`;
}
},
enumerable: false
});
let obj = {a: 'b', c: 'd'};
for(let kv of obj) {
console.log(kv); // a-b c-d
}
In practice
With the technique in hand, we can make custom datatypes iterable.
class Group {
constructor() {
this._data = [];
}
add(it) {
this._data.push(it);
}
delete(it) {
let index = this._data.indexOf(it);
if(index >= 0) {
this._data.splice(index, 1);
}
}
has(it) {
return this._data.includes(it);
}
[Symbol.iterator]() {
let index = 0;
return {
next: () => ({
value: this._data[index++],
done: index > this._data.length
})
};
}
static from(iterable) {
let group = new Group();
for(let item of iterable) {
group.add(item);
}
return group;
}
}
let group = Group.from(['a', 'b', 'c']);
console.log(group)
for (let value of group) {
console.log(value);
}
console.log([...group]);
Reference
Notice
- If you want to follow the latest news/articles for the series of reading notes, Please 「Watch」to Subscribe.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。