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:
commit
86b5a9c33f
@ -722,9 +722,10 @@ async function f() {
|
||||
注意,异步遍历器的`next`方法是可以连续调用的,不必等到上一步产生的 Promise 对象`resolve`以后再调用。这种情况下,`next`方法会累积起来,自动按照每一步的顺序运行下去。下面是一个例子,把所有的`next`方法放在`Promise.all`方法里面。
|
||||
|
||||
```javascript
|
||||
const asyncGenObj = createAsyncIterable(['a', 'b']);
|
||||
const asyncIterable = createAsyncIterable(['a', 'b']);
|
||||
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
|
||||
const [{value: v1}, {value: v2}] = await Promise.all([
|
||||
asyncGenObj.next(), asyncGenObj.next()
|
||||
asyncIterator.next(), asyncIterator.next()
|
||||
]);
|
||||
|
||||
console.log(v1, v2); // a b
|
||||
|
@ -44,7 +44,7 @@ let cp = new ColorPoint(); // ReferenceError
|
||||
|
||||
上面代码中,`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`方法。
|
||||
|
||||
@ -60,7 +60,7 @@ class ColorPoint extends Point {
|
||||
}
|
||||
```
|
||||
|
||||
另一个需要注意的地方是,在子类的构造函数中,只有调用`super`之后,才可以使用`this`关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有`super`方法才能返回父类实例。
|
||||
另一个需要注意的地方是,在子类的构造函数中,只有调用`super`之后,才可以使用`this`关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有`super`方法才能调用父类实例。
|
||||
|
||||
```javascript
|
||||
class Point {
|
||||
@ -452,8 +452,6 @@ Object.create(A.prototype);
|
||||
B.prototype.__proto__ = A.prototype;
|
||||
```
|
||||
|
||||
### extends 的继承目标
|
||||
|
||||
`extends`关键字后面可以跟多种类型的值。
|
||||
|
||||
```javascript
|
||||
@ -463,9 +461,7 @@ class B extends A {
|
||||
|
||||
上面代码的`A`,只要是一个有`prototype`属性的函数,就能被`B`继承。由于函数都有`prototype`属性(除了`Function.prototype`函数),因此`A`可以是任意函数。
|
||||
|
||||
下面,讨论三种特殊情况。
|
||||
|
||||
第一种特殊情况,子类继承`Object`类。
|
||||
下面,讨论两种情况。第一种,子类继承`Object`类。
|
||||
|
||||
```javascript
|
||||
class A extends Object {
|
||||
@ -477,7 +473,7 @@ A.prototype.__proto__ === Object.prototype // true
|
||||
|
||||
这种情况下,`A`其实就是构造函数`Object`的复制,`A`的实例就是`Object`的实例。
|
||||
|
||||
第二种特殊情况,不存在任何继承。
|
||||
第二种情况,不存在任何继承。
|
||||
|
||||
```javascript
|
||||
class A {
|
||||
@ -489,24 +485,6 @@ A.prototype.__proto__ === Object.prototype // true
|
||||
|
||||
这种情况下,`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__`属性。也就是说,子类的原型的原型,是父类的原型。
|
||||
@ -713,8 +691,8 @@ function mix(...mixins) {
|
||||
class Mix {}
|
||||
|
||||
for (let mixin of mixins) {
|
||||
copyProperties(Mix, mixin); // 拷贝实例属性
|
||||
copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
|
||||
copyProperties(Mix.prototype, mixin); // 拷贝实例属性
|
||||
copyProperties(Mix.prototype, Reflect.getPrototypeOf(mixin)); // 拷贝原型属性
|
||||
}
|
||||
|
||||
return Mix;
|
||||
|
@ -475,7 +475,7 @@ for (let x of obj) {
|
||||
|
||||
遍历器对象除了具有`next`方法,还可以具有`return`方法和`throw`方法。如果你自己写遍历器对象生成函数,那么`next`方法是必须部署的,`return`方法和`throw`方法是否部署是可选的。
|
||||
|
||||
`return`方法的使用场合是,如果`for...of`循环提前退出(通常是因为出错,或者有`break`语句或`continue`语句),就会调用`return`方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署`return`方法。
|
||||
`return`方法的使用场合是,如果`for...of`循环提前退出(通常是因为出错,或者有`break`语句),就会调用`return`方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署`return`方法。
|
||||
|
||||
```javascript
|
||||
function readLinesSync(file) {
|
||||
@ -495,7 +495,7 @@ function readLinesSync(file) {
|
||||
}
|
||||
```
|
||||
|
||||
上面代码中,函数`readLinesSync`接受一个文件对象作为参数,返回一个遍历器对象,其中除了`next`方法,还部署了`return`方法。下面的三种情况,都会触发执行`return`方法。
|
||||
上面代码中,函数`readLinesSync`接受一个文件对象作为参数,返回一个遍历器对象,其中除了`next`方法,还部署了`return`方法。下面的两种情况,都会触发执行`return`方法。
|
||||
|
||||
```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)) {
|
||||
console.log(line);
|
||||
throw new Error();
|
||||
}
|
||||
```
|
||||
|
||||
上面代码中,情况一输出文件的第一行以后,就会执行`return`方法,关闭这个文件;情况二输出所有行以后,执行`return`方法,关闭该文件;情况三会在执行`return`方法关闭文件之后,再抛出错误。
|
||||
上面代码中,情况一输出文件的第一行以后,就会执行`return`方法,关闭这个文件;情况二会在执行`return`方法关闭文件之后,再抛出错误。
|
||||
|
||||
注意,`return`方法必须返回一个对象,这是 Generator 规格决定的。
|
||||
|
||||
|
@ -591,7 +591,7 @@ ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面
|
||||
|
||||
- 全局环境中,`this`会返回顶层对象。但是,Node 模块和 ES6 模块中,`this`返回的是当前模块。
|
||||
- 函数里面的`this`,如果函数不是作为对象的方法运行,而是单纯作为函数运行,`this`会指向顶层对象。但是,严格模式下,这时`this`会返回`undefined`。
|
||||
- 不管是严格模式,还是普通模式,`new Function('return this')()`,总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全政策),那么`eval`、`new Function`这些方法都可能无法使用。
|
||||
- 不管是严格模式,还是普通模式,`new Function('return this')()`,总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么`eval`、`new Function`这些方法都可能无法使用。
|
||||
|
||||
综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。
|
||||
|
||||
|
@ -453,7 +453,7 @@ export default 42;
|
||||
export 42;
|
||||
```
|
||||
|
||||
上面代码中,后一句报错是因为没有指定对外的接口,而前一句指定外对接口为`default`。
|
||||
上面代码中,后一句报错是因为没有指定对外的接口,而前一句指定对外接口为`default`。
|
||||
|
||||
有了`export default`命令,输入模块时就非常直观了,以输入 lodash 模块为例。
|
||||
|
||||
@ -643,7 +643,7 @@ export {users} from './users';
|
||||
|
||||
```javascript
|
||||
// script.js
|
||||
import {db, users} from './index';
|
||||
import {db, users} from './constants/index';
|
||||
```
|
||||
|
||||
## import()
|
||||
|
@ -1426,8 +1426,6 @@ let newVersion = {
|
||||
```javascript
|
||||
let aWithDefaults = { x: 1, y: 2, ...a };
|
||||
// 等同于
|
||||
even if property keys don’t clash, because objects record insertion order:
|
||||
|
||||
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
|
||||
{...{}, a: 1}
|
||||
// { a: 1 }
|
||||
even if property keys don’t clash, because objects record insertion order:
|
||||
|
||||
```
|
||||
|
||||
如果扩展运算符的参数是`null`或`undefined`,这两个值会被忽略,不会报错。
|
||||
|
Loading…
x
Reference in New Issue
Block a user