#### 迭代器
```
var a = [1, 2, 3];
var it = a[Symbol.iterator]();
it.next(); //{value: 1, done: false}
it.next(); //{value: 2, done: false}
it.next(); //{value: 3, done: false}
it.next(); //{value: undefined, done: true}
//你可以把[1, 2, 3]看成是[yield 1, yield 2, yield 3],這樣你就明白為什么value為3時done還是false了
var str = "hello world";
var _it = str[Symbol.iterator]();
_it.next(); //{value: h, done: false};
...
//str并不能迭代,而是js幫你通過封箱技術封裝成了String對象
//Array String Generator Collection/TypedArray 允許迭代
```
迭代器如果throw了一個error但是沒有在上下文中捕獲,那么會導致整個迭代器終止
迭代器本身是iterable,那它可以直接用于for of循環
```
//你可以通過為迭代器提供一個Symbol.iterator并返回自身來使其成為iterable
var it = {
[Symbol.iterator]() {return this;},
next() {
return { value: this.i++, done: this.i > 5 ? true : false };
},
i: 0
}
for(var i of it) { console.log(i); } //0 1 2 3 4
```
還記得之前的例子嗎?[1, 2, 3]迭代后value為3的done并不是true,因為
```
for(var val, res, it = a[Symbol.iterator](); (res = it.next()) && !res.done)
```
的判斷條件一旦done為true,此時循環就結束了,最后一個值將無法獲取,因此es6規定[1, 2, 3]遍歷完后的下一個next的done才是true
迭代器消耗
除了for of外,解構也可以消耗迭代器
```
var a = [1, 2, 3, 4, 5];
var it = a[Symbol.iterator]();
var [x, y] = it;
var [z, ...w] = it;
//一樣的,再調一次nextdone才是true
it.next(); //{value: undefined, done: true}
x; //1
y; //2
z; //3
w; //[4, 5]
```
#### 生成器
```
yield 3 //合法
a = 2 * (yield) //合法
a = 2 * yield 3 //不合法
a = 2 * (yield 3) //合法
```
yield優先級很低很低,僅次于spread運算符和...
```
yield 2 + 3 相當于yield (2 + 3)
//因此,用()
(yield 2) + 3
```
```
function *foo() {
yield 1;
yield 2;
yield 3;
return 4;
}
function *bar() {
var x = yield *foo();
console.log("x:", x);
}
for(var i of bar()){ console.log(i) }
//1 2 3
//x: 4
```
提前完成
```
function *foo() {
yield 1;
yield 2;
yield 3
}
var it = foo();
it.next(); //{value: 1, done: false}
it.return(4); //{value: 4, done: true}
it.next(); //{value: undefined, done: true}
it.next(5); //{value: undefined, done: true}
//it.throw如果在迭代器內部沒有做出異常處理的化,迭代器一樣會提前結束
function *foo() {
//沒有做異常處理try catch
yield 1;
yield 2;
yield 3;
}
var it = foo();
it.next(); //{value: 1, done: false}
try {
it.throw(4); //{value: 4, done: true}
}
catch(err) {
console.log(err);
}
it.next(); //{value: undefined, done: true}
```
```
function *foo() {
//做了處理
try {
yield 1;
}
catch(err) {console.log(err)}
yield 2;
yield 3;
}
var it = foo();
it.next(); //{value: 1, done: false}
it.throw(4);//4 //{value: 2, done: false}
```
foo()每次都會創建一個新的迭代器,而不是多個迭代器公用一個foo()
#### 模塊
```
var foo = 2;
export foo; //導出2
export {foo}; //導出{foo: 2}
export {foo as bar}; //導出{bar: 2} 相當于模塊重命名
export {foo as default}; //相當于export default foo;
export {a: {}, b: {}};
//每個js文件可以有多個導出,但只能有一個默認導出
import {foo} from ...;
import {bar} from ...;
import foo from ...;
import {a, b} from ...;或import * from ...;或import * as o from ...;
//import也可以重命名
import {foo as _foo} from ...;
```
所有導入的模塊應當是只讀的,否則用戶很有可能修改了模塊本身,這是不行的
```
import * as foo from ...;
foo = {}; //TypeError
foo.a = 1; //TypeError
```
#### 類
```
class Foo {
constructor(a, b) {
this.x = a;
this.y = b;
}
gimmeXY() { return this.x * this.y }
}
//類似于
function Foo(a, b) { this.x = a; this.y = b; }
Foo.prototype.gimmeXY = function() { return this.x * this.y }
```
```
class Bar extends Foo {
constructor(a, b, c) {
super(a, b);
this.z = c;
}
gimmeXYZ() { super.gimmeXY() * this.z; }
}
var b = new Bar(5, 15, 25);
b.x; //5
b.y; //15
b.z; //25
b.gimmeXYZ(); //1875
//A extends B相當于把A的prototype的[[Prototype]]鏈接到B的prototype中
//A.prototype = Object.create(B.prototype)
```
```
class ParentA {
constructor() { this.id = "a"; }
foo() { console.log("ParentA:", this.id); }
}
class ParentB {
constructor() { this.id = "b"; }
foo() { console.log("ParentB:", this.id); }
}
class ChildA extends ParentA {
foo() { super.foo(); console.log("ChildA:", this.id); }
}
class ChildB extends ParentB {
foo() { super.foo(); console.log("ChildB:", this.id); }
}
var a = new ChildA();
a.foo(); //ParentA: a //ChildA: a
var b = new ChildB();
b.foo(); //ParentB: b //ChildB: b
b.foo.call(a); //ParentB: a //ChildB: a
```
static指定的屬性是直接創建在函數上的而不是函數的原型上
```
class Bar {
static net() { console.log(".net") }
}
Bar.net(); //.net
var b = new Bar();
b.net; //undefined
//這是當然的了,因為
function Bar() {
net() { console.log(".net") }
}
var b = new Bar();
b.net; //undefined
```
new.target(元屬性)
```
//new.target總是指向new實際上直接調用的構造器
class Foo {
constructor() { console.log("Foo:", new.target.name) }
}
class Bar extends Foo {
constructor() { super(); console.log("Bar:", new.target.name)}
baz() { console.log("baz:", new.target.name) }
}
var a = new Foo(); //Foo: Foo
var b= new Bar(); //Foo: Bar //Bar: Bar
b.baz(); //baz: undefined
```
- 你不知道的JS上
- 第一部分 第三章 函數作用域和塊作用域
- 第一部分 第四章 提升
- 第一部分 第五章 閉包
- 第二部分 第一章 關于this
- 第二部分 第二章 this全面解析
- 第二部分 第三章 對象
- 第二部分 第五章 原型
- 第二部分 第六章 行為委托
- 你不知道的JS中
- 第一部分 第二章 值
- 第一部分 第三章 原生函數
- 第一部分 第四章 強制類型轉換
- 第一部分 第五章 語法
- 第二部分 第一章 異步
- 第二部分 第三章 Promise
- 第二部分 第四章 生成器
- 第二部分 第五章 性能
- 你不知道的JS下
- 第一部分 總結
- 第二部分 第二章 語法
- 第二部分 第三章 代碼組織
- 第二部分 第四章 Promise
- 第二部分 第五章 集合
- 第二部分 第六章 新增API
- 第二部分 第七章 元編程
- 第二部分 第八章 ES6之后