Skip to content

Commit 14c45fe

Browse files
committed
doc: update to ES2018
1 parent 5d5f588 commit 14c45fe

File tree

5 files changed

+134
-108
lines changed

5 files changed

+134
-108
lines changed

docs/async.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ async function logInOrder(urls) {
661661

662662
这里隐含着一个规定,`next`方法必须是同步的,只要调用就必须立刻返回值。也就是说,一旦执行`next`方法,就必须同步地得到`value``done`这两个属性。如果遍历指针正好指向同步操作,当然没有问题,但对于异步操作,就不太合适了。目前的解决方法是,Generator 函数里面的异步操作,返回一个 Thunk 函数或者 Promise 对象,即`value`属性是一个 Thunk 函数或者 Promise 对象,等待以后返回真正的值,而`done`属性则还是同步产生的。
663663

664-
目前,有一个[提案](https://github.com/tc39/proposal-async-iteration),为异步操作提供原生的遍历器接口,即`value``done`这两个属性都是异步产生,这称为”异步遍历器“(Async Iterator)
664+
ES2018 [引入](https://github.com/tc39/proposal-async-iteration)了”异步遍历器“(Async Iterator),为异步操作提供原生的遍历器接口,即`value``done`这两个属性都是异步产生。
665665

666666
### 异步遍历的接口
667667

docs/object.md

Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,11 +1255,11 @@ a // 1
12551255
b // [2, 3]
12561256
```
12571257

1258-
ES2017 将这个运算符[引入](https://github.com/sebmarkbage/ecmascript-rest-spread)了对象。
1258+
ES2018 将这个运算符[引入](https://github.com/sebmarkbage/ecmascript-rest-spread)了对象。
12591259

1260-
**(1)解构赋值**
1260+
### 解构赋值
12611261

1262-
对象的解构赋值用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
1262+
对象的解构赋值用于从一个对象取值,相当于将目标对象自身的所有可遍历的(enumerable)、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
12631263

12641264
```javascript
12651265
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
@@ -1331,17 +1331,17 @@ function baseFunction({ a, b }) {
13311331
// ...
13321332
}
13331333
function wrapperFunction({ x, y, ...restConfig }) {
1334-
// 使用x和y参数进行操作
1334+
// 使用 x 和 y 参数进行操作
13351335
// 其余参数传给原始函数
13361336
return baseFunction(restConfig);
13371337
}
13381338
```
13391339

13401340
上面代码中,原始函数`baseFunction`接受`a``b`作为参数,函数`wrapperFunction``baseFunction`的基础上进行了扩展,能够接受多余的参数,并且保留原始函数的行为。
13411341

1342-
**(2)扩展运算符**
1342+
### 扩展运算符
13431343

1344-
扩展运算符`...`)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
1344+
对象的扩展运算符`...`)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
13451345

13461346
```javascript
13471347
let z = { a: 3, b: 4 };
@@ -1419,6 +1419,8 @@ let newVersion = {
14191419
```javascript
14201420
let aWithDefaults = { x: 1, y: 2, ...a };
14211421
// 等同于
1422+
even if property keys don’t clash, because objects record insertion order:
1423+
14221424
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
14231425
// 等同于
14241426
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
@@ -1438,6 +1440,8 @@ const obj = {
14381440
```javascript
14391441
{...{}, a: 1}
14401442
// { a: 1 }
1443+
even if property keys don’t clash, because objects record insertion order:
1444+
14411445
```
14421446

14431447
如果扩展运算符的参数是`null``undefined`,这两个值会被忽略,不会报错。
@@ -1468,45 +1472,3 @@ let runtimeError = {
14681472
};
14691473
```
14701474

1471-
## Null 传导运算符
1472-
1473-
编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在。比如,要读取`message.body.user.firstName`,安全的写法是写成下面这样。
1474-
1475-
```javascript
1476-
const firstName = (message
1477-
&& message.body
1478-
&& message.body.user
1479-
&& message.body.user.firstName) || 'default';
1480-
```
1481-
1482-
这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/claudepache/es-optional-chaining),引入了“Null 传导运算符”(null propagation operator)`?.`,简化上面的写法。
1483-
1484-
```javascript
1485-
const firstName = message?.body?.user?.firstName || 'default';
1486-
```
1487-
1488-
上面代码有三个`?.`运算符,只要其中一个返回`null``undefined`,就不再往下运算,而是返回`undefined`
1489-
1490-
“Null 传导运算符”有四种用法。
1491-
1492-
- `obj?.prop` // 读取对象属性
1493-
- `obj?.[expr]` // 同上
1494-
- `func?.(...args)` // 函数或对象方法的调用
1495-
- `new C?.(...args)` // 构造函数的调用
1496-
1497-
传导运算符之所以写成`obj?.prop`,而不是`obj?prop`,是为了方便编译器能够区分三元运算符`?:`(比如`obj?prop:123`)。
1498-
1499-
下面是更多的例子。
1500-
1501-
```javascript
1502-
// 如果 a 是 null 或 undefined, 返回 undefined
1503-
// 否则返回 a.b.c().d
1504-
a?.b.c().d
1505-
1506-
// 如果 a 是 null 或 undefined,下面的语句不产生任何效果
1507-
// 否则执行 a.b = 42
1508-
a?.b = 42
1509-
1510-
// 如果 a 是 null 或 undefined,下面的语句不产生任何效果
1511-
delete a?.b
1512-
```

docs/promise.md

Lines changed: 79 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,85 @@ someAsyncThing().then(function() {
486486

487487
上面代码中,第二个`catch`方法用来捕获,前一个`catch`方法抛出的错误。
488488

489+
## Promise.prototype.finally()
490+
491+
`finally`方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
492+
493+
```javascript
494+
promise
495+
.then(result => {···})
496+
.catch(error => {···})
497+
.finally(() => {···});
498+
```
499+
500+
上面代码中,不管`promise`最后的状态,在执行完`then``catch`指定的回调函数以后,都会执行`finally`方法指定的回调函数。
501+
502+
下面是一个例子,服务器使用 Promise 处理请求,然后使用`finally`方法关掉服务器。
503+
504+
```javascript
505+
server.listen(port)
506+
.then(function () {
507+
// ...
508+
})
509+
.finally(server.stop);
510+
```
511+
512+
`finally`方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是`fulfilled`还是`rejected`。这表明,`finally`方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
513+
514+
`finally`本质上是`then`方法的特例。
515+
516+
```javascript
517+
promise
518+
.finally(() => {
519+
// 语句
520+
});
521+
522+
// 等同于
523+
promise
524+
.then(
525+
result => {
526+
// 语句
527+
return result;
528+
},
529+
error => {
530+
// 语句
531+
throw error;
532+
}
533+
);
534+
```
535+
536+
上面代码中,如果不使用`finally`方法,同样的语句需要为成功和失败两种情况各写一次。有了`finally`方法,则只需要写一次。
537+
538+
它的实现也很简单。
539+
540+
```javascript
541+
Promise.prototype.finally = function (callback) {
542+
let P = this.constructor;
543+
return this.then(
544+
value => P.resolve(callback()).then(() => value),
545+
reason => P.resolve(callback()).then(() => { throw reason })
546+
);
547+
};
548+
```
549+
550+
上面代码中,不管前面的 Promise 是`fulfilled`还是`rejected`,都会执行回调函数`callback`
551+
552+
从上面的实现还可以看到,`finally`方法总是会返回原来的值。
553+
554+
```javascript
555+
// resolve 的值是 undefined
556+
Promise.resolve(2).then(() => {}, () => {})
557+
558+
// resolve 的值是 2
559+
Promise.resolve(2).finally(() => {})
560+
561+
// reject 的值是 undefined
562+
Promise.reject(3).then(() => {}, () => {})
563+
564+
// reject 的值是 3
565+
Promise.reject(3).finally(() => {})
566+
```
567+
489568
## Promise.all()
490569

491570
`Promise.all`方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
@@ -747,64 +826,6 @@ Promise.reject(thenable)
747826

748827
上面代码中,`Promise.reject`方法的参数是一个`thenable`对象,执行以后,后面`catch`方法的参数不是`reject`抛出的“出错了”这个字符串,而是`thenable`对象。
749828

750-
## 两个有用的附加方法
751-
752-
ES6 的 Promise API 提供的方法不是很多,有些有用的方法可以自己部署。下面介绍如何部署两个不在 ES6 之中、但很有用的方法。
753-
754-
### done()
755-
756-
Promise 对象的回调链,不管以`then`方法或`catch`方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局)。因此,我们可以提供一个`done`方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。
757-
758-
```javascript
759-
asyncFunc()
760-
.then(f1)
761-
.catch(r1)
762-
.then(f2)
763-
.done();
764-
```
765-
766-
它的实现代码相当简单。
767-
768-
```javascript
769-
Promise.prototype.done = function (onFulfilled, onRejected) {
770-
this.then(onFulfilled, onRejected)
771-
.catch(function (reason) {
772-
// 抛出一个全局错误
773-
setTimeout(() => { throw reason }, 0);
774-
});
775-
};
776-
```
777-
778-
从上面代码可见,`done`方法的使用,可以像`then`方法那样用,提供`fulfilled``rejected`状态的回调函数,也可以不提供任何参数。但不管怎样,`done`都会捕捉到任何可能出现的错误,并向全局抛出。
779-
780-
### finally()
781-
782-
`finally`方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。它与`done`方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
783-
784-
下面是一个例子,服务器使用 Promise 处理请求,然后使用`finally`方法关掉服务器。
785-
786-
```javascript
787-
server.listen(0)
788-
.then(function () {
789-
// run test
790-
})
791-
.finally(server.stop);
792-
```
793-
794-
它的实现也很简单。
795-
796-
```javascript
797-
Promise.prototype.finally = function (callback) {
798-
let P = this.constructor;
799-
return this.then(
800-
value => P.resolve(callback()).then(() => value),
801-
reason => P.resolve(callback()).then(() => { throw reason })
802-
);
803-
};
804-
```
805-
806-
上面代码中,不管前面的 Promise 是`fulfilled`还是`rejected`,都会执行回调函数`callback`
807-
808829
## 应用
809830

810831
### 加载图片

docs/proposals.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,46 @@ class Product {
117117
上面代码中,`throw`都出现在表达式里面。
118118

119119
语法上,`throw`表达式里面的`throw`不再是一个命令,而是一个运算符。为了避免与`throw`命令混淆,规定`throw`出现在行首,一律解释为`throw`语句,而不是`throw`表达式。
120+
121+
## Null 传导运算符
122+
123+
编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在。比如,要读取`message.body.user.firstName`,安全的写法是写成下面这样。
124+
125+
```javascript
126+
const firstName = (message
127+
&& message.body
128+
&& message.body.user
129+
&& message.body.user.firstName) || 'default';
130+
```
131+
132+
这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/claudepache/es-optional-chaining),引入了“Null 传导运算符”(null propagation operator)`?.`,简化上面的写法。
133+
134+
```javascript
135+
const firstName = message?.body?.user?.firstName || 'default';
136+
```
137+
138+
上面代码有三个`?.`运算符,只要其中一个返回`null``undefined`,就不再往下运算,而是返回`undefined`
139+
140+
“Null 传导运算符”有四种用法。
141+
142+
- `obj?.prop` // 读取对象属性
143+
- `obj?.[expr]` // 同上
144+
- `func?.(...args)` // 函数或对象方法的调用
145+
- `new C?.(...args)` // 构造函数的调用
146+
147+
传导运算符之所以写成`obj?.prop`,而不是`obj?prop`,是为了方便编译器能够区分三元运算符`?:`(比如`obj?prop:123`)。
148+
149+
下面是更多的例子。
150+
151+
```javascript
152+
// 如果 a 是 null 或 undefined, 返回 undefined
153+
// 否则返回 a.b.c().d
154+
a?.b.c().d
155+
156+
// 如果 a 是 null 或 undefined,下面的语句不产生任何效果
157+
// 否则执行 a.b = 42
158+
a?.b = 42
159+
160+
// 如果 a 是 null 或 undefined,下面的语句不产生任何效果
161+
delete a?.b
162+
```

docs/string.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ Breve over the h goes \u{h}ere // 报错
933933

934934
模板字符串会将`\u00FF``\u{42}`当作 Unicode 字符进行转义,所以`\unicode`解析时报错;而`\x56`会被当作十六进制字符串转义,所以`\xerxes`会报错。也就是说,`\u``\x`在 LaTEX 里面有特殊含义,但是 JavaScript 将它们转义了。
935935

936-
为了解决这个问题,现在有一个[提案](https://tc39.github.io/proposal-template-literal-revision/),放松对标签模板里面的字符串转义的限制。如果遇到不合法的字符串转义,就返回`undefined`,而不是报错,并且从`raw`属性上面可以得到原始字符串。
936+
为了解决这个问题,ES2018 [放松](https://tc39.github.io/proposal-template-literal-revision/)了对标签模板里面的字符串转义的限制。如果遇到不合法的字符串转义,就返回`undefined`,而不是报错,并且从`raw`属性上面可以得到原始字符串。
937937

938938
```javascript
939939
function tag(strs) {

0 commit comments

Comments
 (0)