1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

docs(let): fix const #720

This commit is contained in:
ruanyf 2018-07-17 21:45:13 +08:00
commit 86b5a9c33f
6 changed files with 15 additions and 46 deletions

View File

@ -722,9 +722,10 @@ async function f() {
注意,异步遍历器的`next`方法是可以连续调用的,不必等到上一步产生的 Promise 对象`resolve`以后再调用。这种情况下,`next`方法会累积起来,自动按照每一步的顺序运行下去。下面是一个例子,把所有的`next`方法放在`Promise.all`方法里面。 注意,异步遍历器的`next`方法是可以连续调用的,不必等到上一步产生的 Promise 对象`resolve`以后再调用。这种情况下,`next`方法会累积起来,自动按照每一步的顺序运行下去。下面是一个例子,把所有的`next`方法放在`Promise.all`方法里面。
```javascript ```javascript
const asyncGenObj = createAsyncIterable(['a', 'b']); const asyncIterable = createAsyncIterable(['a', 'b']);
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
const [{value: v1}, {value: v2}] = await Promise.all([ const [{value: v1}, {value: v2}] = await Promise.all([
asyncGenObj.next(), asyncGenObj.next() asyncIterator.next(), asyncIterator.next()
]); ]);
console.log(v1, v2); // a b console.log(v1, v2); // a b

View File

@ -44,7 +44,7 @@ let cp = new ColorPoint(); // ReferenceError
上面代码中,`ColorPoint`继承了父类`Point`,但是它的构造函数没有调用`super`方法,导致新建实例时报错。 上面代码中,`ColorPoint`继承了父类`Point`,但是它的构造函数没有调用`super`方法,导致新建实例时报错。
ES5 的继承,实质是先创造子类的实例对象`this`,然后再将父类的方法添加到`this`上面(`Parent.apply(this)`。ES6 的继承机制完全不同,实质是先创造父类的实例对象`this`(所以必须先调用`super`方法),然后再用子类的构造函数修改`this` ES5 的继承,实质是先创造子类的实例对象`this`,然后再将父类的方法添加到`this`上面(`Parent.apply(this)`。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到`this`上面(所以必须先调用`super`方法),然后再用子类的构造函数修改`this`
如果子类没有定义`constructor`方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有`constructor`方法。 如果子类没有定义`constructor`方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有`constructor`方法。
@ -60,7 +60,7 @@ class ColorPoint extends Point {
} }
``` ```
另一个需要注意的地方是,在子类的构造函数中,只有调用`super`之后,才可以使用`this`关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有`super`方法才能返回父类实例。 另一个需要注意的地方是,在子类的构造函数中,只有调用`super`之后,才可以使用`this`关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有`super`方法才能调用父类实例。
```javascript ```javascript
class Point { class Point {
@ -452,8 +452,6 @@ Object.create(A.prototype);
B.prototype.__proto__ = A.prototype; B.prototype.__proto__ = A.prototype;
``` ```
### extends 的继承目标
`extends`关键字后面可以跟多种类型的值。 `extends`关键字后面可以跟多种类型的值。
```javascript ```javascript
@ -463,9 +461,7 @@ class B extends A {
上面代码的`A`,只要是一个有`prototype`属性的函数,就能被`B`继承。由于函数都有`prototype`属性(除了`Function.prototype`函数),因此`A`可以是任意函数。 上面代码的`A`,只要是一个有`prototype`属性的函数,就能被`B`继承。由于函数都有`prototype`属性(除了`Function.prototype`函数),因此`A`可以是任意函数。
下面,讨论三种特殊情况。 下面,讨论两种情况。第一种,子类继承`Object`类。
第一种特殊情况,子类继承`Object`类。
```javascript ```javascript
class A extends Object { class A extends Object {
@ -477,7 +473,7 @@ A.prototype.__proto__ === Object.prototype // true
这种情况下,`A`其实就是构造函数`Object`的复制,`A`的实例就是`Object`的实例。 这种情况下,`A`其实就是构造函数`Object`的复制,`A`的实例就是`Object`的实例。
第二种特殊情况,不存在任何继承。 第二种情况,不存在任何继承。
```javascript ```javascript
class A { class A {
@ -489,24 +485,6 @@ A.prototype.__proto__ === Object.prototype // true
这种情况下,`A`作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承`Function.prototype`。但是,`A`调用后返回一个空对象(即`Object`实例),所以`A.prototype.__proto__`指向构造函数(`Object`)的`prototype`属性。 这种情况下,`A`作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承`Function.prototype`。但是,`A`调用后返回一个空对象(即`Object`实例),所以`A.prototype.__proto__`指向构造函数(`Object`)的`prototype`属性。
第三种特殊情况,子类继承`null`
```javascript
class A extends null {
}
A.__proto__ === Function.prototype // true
A.prototype.__proto__ === undefined // true
```
这种情况与第二种情况非常像。`A`也是一个普通函数,所以直接继承`Function.prototype`。但是,`A`调用后返回的对象不继承任何方法,所以它的`__proto__`指向`undefined`,即实质上执行了下面的代码。
```javascript
class C extends null {
constructor() { return Object.create(null); }
}
```
### 实例的 \_\_proto\_\_ 属性 ### 实例的 \_\_proto\_\_ 属性
子类实例的`__proto__`属性的`__proto__`属性,指向父类实例的`__proto__`属性。也就是说,子类的原型的原型,是父类的原型。 子类实例的`__proto__`属性的`__proto__`属性,指向父类实例的`__proto__`属性。也就是说,子类的原型的原型,是父类的原型。
@ -713,8 +691,8 @@ function mix(...mixins) {
class Mix {} class Mix {}
for (let mixin of mixins) { for (let mixin of mixins) {
copyProperties(Mix, mixin); // 拷贝实例属性 copyProperties(Mix.prototype, mixin); // 拷贝实例属性
copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性 copyProperties(Mix.prototype, Reflect.getPrototypeOf(mixin)); // 拷贝原型属性
} }
return Mix; return Mix;

View File

@ -475,7 +475,7 @@ for (let x of obj) {
遍历器对象除了具有`next`方法,还可以具有`return`方法和`throw`方法。如果你自己写遍历器对象生成函数,那么`next`方法是必须部署的,`return`方法和`throw`方法是否部署是可选的。 遍历器对象除了具有`next`方法,还可以具有`return`方法和`throw`方法。如果你自己写遍历器对象生成函数,那么`next`方法是必须部署的,`return`方法和`throw`方法是否部署是可选的。
`return`方法的使用场合是,如果`for...of`循环提前退出(通常是因为出错,或者有`break`语句`continue`语句),就会调用`return`方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署`return`方法。 `return`方法的使用场合是,如果`for...of`循环提前退出(通常是因为出错,或者有`break`语句),就会调用`return`方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署`return`方法。
```javascript ```javascript
function readLinesSync(file) { function readLinesSync(file) {
@ -495,7 +495,7 @@ function readLinesSync(file) {
} }
``` ```
上面代码中,函数`readLinesSync`接受一个文件对象作为参数,返回一个遍历器对象,其中除了`next`方法,还部署了`return`方法。下面的种情况,都会触发执行`return`方法。 上面代码中,函数`readLinesSync`接受一个文件对象作为参数,返回一个遍历器对象,其中除了`next`方法,还部署了`return`方法。下面的种情况,都会触发执行`return`方法。
```javascript ```javascript
// 情况一 // 情况一
@ -505,19 +505,13 @@ for (let line of readLinesSync(fileName)) {
} }
// 情况二 // 情况二
for (let line of readLinesSync(fileName)) {
console.log(line);
continue;
}
// 情况三
for (let line of readLinesSync(fileName)) { for (let line of readLinesSync(fileName)) {
console.log(line); console.log(line);
throw new Error(); throw new Error();
} }
``` ```
上面代码中,情况一输出文件的第一行以后,就会执行`return`方法,关闭这个文件;情况二输出所有行以后,执行`return`方法,关闭该文件;情况三会在执行`return`方法关闭文件之后,再抛出错误。 上面代码中,情况一输出文件的第一行以后,就会执行`return`方法,关闭这个文件;情况二会在执行`return`方法关闭文件之后,再抛出错误。
注意,`return`方法必须返回一个对象,这是 Generator 规格决定的。 注意,`return`方法必须返回一个对象,这是 Generator 规格决定的。

View File

@ -591,7 +591,7 @@ ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面
- 全局环境中,`this`会返回顶层对象。但是Node 模块和 ES6 模块中,`this`返回的是当前模块。 - 全局环境中,`this`会返回顶层对象。但是Node 模块和 ES6 模块中,`this`返回的是当前模块。
- 函数里面的`this`,如果函数不是作为对象的方法运行,而是单纯作为函数运行,`this`会指向顶层对象。但是,严格模式下,这时`this`会返回`undefined` - 函数里面的`this`,如果函数不是作为对象的方法运行,而是单纯作为函数运行,`this`会指向顶层对象。但是,严格模式下,这时`this`会返回`undefined`
- 不管是严格模式,还是普通模式,`new Function('return this')()`,总是会返回全局对象。但是,如果浏览器用了 CSPContent Security Policy内容安全策),那么`eval``new Function`这些方法都可能无法使用。 - 不管是严格模式,还是普通模式,`new Function('return this')()`,总是会返回全局对象。但是,如果浏览器用了 CSPContent Security Policy内容安全策),那么`eval``new Function`这些方法都可能无法使用。
综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。 综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。

View File

@ -453,7 +453,7 @@ export default 42;
export 42; export 42;
``` ```
上面代码中,后一句报错是因为没有指定对外的接口,而前一句指定对接口为`default` 上面代码中,后一句报错是因为没有指定对外的接口,而前一句指定对接口为`default`
有了`export default`命令,输入模块时就非常直观了,以输入 lodash 模块为例。 有了`export default`命令,输入模块时就非常直观了,以输入 lodash 模块为例。
@ -643,7 +643,7 @@ export {users} from './users';
```javascript ```javascript
// script.js // script.js
import {db, users} from './index'; import {db, users} from './constants/index';
``` ```
## import() ## import()

View File

@ -1426,8 +1426,6 @@ let newVersion = {
```javascript ```javascript
let aWithDefaults = { x: 1, y: 2, ...a }; let aWithDefaults = { x: 1, y: 2, ...a };
// 等同于 // 等同于
even if property keys dont clash, because objects record insertion order:
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a); let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
// 等同于 // 等同于
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a); let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
@ -1447,8 +1445,6 @@ const obj = {
```javascript ```javascript
{...{}, a: 1} {...{}, a: 1}
// { a: 1 } // { a: 1 }
even if property keys dont clash, because objects record insertion order:
``` ```
如果扩展运算符的参数是`null``undefined`,这两个值会被忽略,不会报错。 如果扩展运算符的参数是`null``undefined`,这两个值会被忽略,不会报错。