#### 迭代器
```
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之后