From 01f62521de56400f6275ddc17b0979c971ee1a05 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 22 Feb 2018 22:42:03 +0800 Subject: [PATCH 001/492] docs(funcion): fix double colon --- docs/function.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/function.md b/docs/function.md index beaa2ac7c..5969a84e0 100644 --- a/docs/function.md +++ b/docs/function.md @@ -944,23 +944,15 @@ let log = ::console.log; var log = console.log.bind(console); ``` -双冒号运算符的运算结果,还是一个函数,因此可以采用链式写法。 +如果双冒号运算符的运算结果,还是一个对象,就可以采用链式写法。 ```javascript -// 例一 import { map, takeWhile, forEach } from "iterlib"; getPlayers() ::map(x => x.character()) ::takeWhile(x => x.strength > 100) ::forEach(x => console.log(x)); - -// 例二 -let { find, html } = jake; - -document.querySelectorAll("div.myClass") -::find("p") -::html("hahaha"); ``` ## 尾调用优化 From 9f82a677ce1d12f527fe43db7b4aa7d7a89c6f40 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Fri, 23 Feb 2018 12:38:44 +0800 Subject: [PATCH 002/492] docs(decorator): fix typo --- docs/decorator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decorator.md b/docs/decorator.md index 7791ace26..52dffceb3 100644 --- a/docs/decorator.md +++ b/docs/decorator.md @@ -103,7 +103,7 @@ let obj = new MyClass(); obj.foo() // 'foo' ``` -上面代码通过修饰器`mixins`,把`Foo`类的方法添加到了`MyClass`的实例上面。可以用`Object.assign()`模拟这个功能。 +上面代码通过修饰器`mixins`,把`Foo`对象的方法添加到了`MyClass`的实例上面。可以用`Object.assign()`模拟这个功能。 ```javascript const Foo = { From c7b5077af4755e236dbb1931c2b5066932867b3f Mon Sep 17 00:00:00 2001 From: cntanglijun <869058216@qq.com> Date: Sun, 25 Feb 2018 00:48:27 +0800 Subject: [PATCH 003/492] =?UTF-8?q?=E5=B0=91=E4=BA=86=E4=B8=80=E4=B8=AA"?= =?UTF-8?q?=E4=B8=AA"=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/generator-async.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator-async.md b/docs/generator-async.md index fd5200953..53966a342 100644 --- a/docs/generator-async.md +++ b/docs/generator-async.md @@ -151,7 +151,7 @@ g.next() // { value: 3, done: false } g.next(2) // { value: 2, done: true } ``` -上面代码中,第一`next`方法的`value`属性,返回表达式`x + 2`的值`3`。第二个`next`方法带有参数`2`,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量`y`接收。因此,这一步的`value`属性,返回的就是`2`(变量`y`的值)。 +上面代码中,第一个`next`方法的`value`属性,返回表达式`x + 2`的值`3`。第二个`next`方法带有参数`2`,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量`y`接收。因此,这一步的`value`属性,返回的就是`2`(变量`y`的值)。 Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。 From df6cc1a71de2b2c11d389709ba9bc38bdce30159 Mon Sep 17 00:00:00 2001 From: yuri Date: Sun, 25 Feb 2018 14:16:22 +0800 Subject: [PATCH 004/492] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=AE=A1=E9=81=93?= =?UTF-8?q?=E8=BF=90=E7=AE=97=E7=AC=A6=E6=8F=90=E6=A1=88=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/proposals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposals.md b/docs/proposals.md index 9ca613f8d..f28f9e61c 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -319,7 +319,7 @@ g(1, 2, 3); // [1, 2, 3, 9, 1, 2, 3] ## 管道运算符 -Unix 操作系统有一个管道机制(pipeline),可以把前一个操作的值传给后一个操作。这个机制非常有用,使得简单的操作可以组合成为复杂的操作。许多语言都有管道的实现,现在有一个[提案](https://github.com/tc39/proposal-partial-application),让 JavaScript 也拥有管道机制。 +Unix 操作系统有一个管道机制(pipeline),可以把前一个操作的值传给后一个操作。这个机制非常有用,使得简单的操作可以组合成为复杂的操作。许多语言都有管道的实现,现在有一个[提案](https://github.com/tc39/proposal-pipeline-operator),让 JavaScript 也拥有管道机制。 JavaScript 的管道是一个运算符,写作`|>`。它的左边是一个表达式,右边是一个函数。管道运算符把左边表达式的值,传入右边的函数进行求值。 From 78d9b668dda9d7b4d8caf3da724596311f0007a9 Mon Sep 17 00:00:00 2001 From: yuri Date: Sun, 25 Feb 2018 14:24:17 +0800 Subject: [PATCH 005/492] =?UTF-8?q?Null=20=E4=BC=A0=E5=AF=BC=E8=BF=90?= =?UTF-8?q?=E7=AE=97=E7=AC=A6=E6=8F=90=E6=A1=88=E5=9C=B0=E5=9D=80=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E4=B8=BAtc39=E5=AE=98=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/proposals.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proposals.md b/docs/proposals.md index 9ca613f8d..97ad41675 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -129,7 +129,7 @@ const firstName = (message && message.body.user.firstName) || 'default'; ``` -这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/claudepache/es-optional-chaining),引入了“Null 传导运算符”(null propagation operator)`?.`,简化上面的写法。 +这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/tc39/proposal-optional-chaining),引入了“Null 传导运算符”(null propagation operator)`?.`,简化上面的写法。 ```javascript const firstName = message?.body?.user?.firstName || 'default'; From be47d277ac5ae9b1a08891ca22fb250262d3166d Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 26 Feb 2018 14:35:53 +0800 Subject: [PATCH 006/492] docs(proposals): edit option chaining operator --- docs/proposals.md | 81 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/docs/proposals.md b/docs/proposals.md index 9ca613f8d..6c2ac6b98 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -118,7 +118,7 @@ class Product { 语法上,`throw`表达式里面的`throw`不再是一个命令,而是一个运算符。为了避免与`throw`命令混淆,规定`throw`出现在行首,一律解释为`throw`语句,而不是`throw`表达式。 -## Null 传导运算符 +## 链判断运算符 编程实务中,如果读取对象内部的某个属性,往往需要判断一下该对象是否存在。比如,要读取`message.body.user.firstName`,安全的写法是写成下面这样。 @@ -129,38 +129,93 @@ const firstName = (message && message.body.user.firstName) || 'default'; ``` -这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/claudepache/es-optional-chaining),引入了“Null 传导运算符”(null propagation operator)`?.`,简化上面的写法。 +这样的层层判断非常麻烦,因此现在有一个[提案](https://github.com/claudepache/es-optional-chaining),引入了“链判断运算符”(optional chaining operator)`?.`,简化上面的写法。 ```javascript const firstName = message?.body?.user?.firstName || 'default'; ``` -上面代码有三个`?.`运算符,只要其中一个返回`null`或`undefined`,就不再往下运算,而是返回`undefined`。 +上面代码有三个`?.`运算符,直接在链式调用的时候判断,左侧的对象是否为`null`或`undefined`。如果是的,就不再往下运算,而是返回`undefined`。 -“Null 传导运算符”有四种用法。 +链判断运算符号有三种用法。 - `obj?.prop` // 读取对象属性 - `obj?.[expr]` // 同上 - `func?.(...args)` // 函数或对象方法的调用 -- `new C?.(...args)` // 构造函数的调用 -传导运算符之所以写成`obj?.prop`,而不是`obj?prop`,是为了方便编译器能够区分三元运算符`?:`(比如`obj?prop:123`)。 +下面是判断函数是否存在的例子。 + +```javascript +iterator.return?.() +``` + +上面代码中,`iterator.return`如果有定义,就会调用该方法,否则直接返回`undefined`。 下面是更多的例子。 ```javascript -// 如果 a 是 null 或 undefined, 返回 undefined -// 否则返回 a.b.c().d -a?.b.c().d +a?.b +// 等同于 +a == null ? undefined : a.b + +a?.[x] +// 等同于 +a == null ? undefined : a[x] + +a?.b() +// 等同于 +a == null ? undefined : a.b() + +a?.() +// 等同于 +a == null ? undefined : a() +``` + +使用这个运算符,有几个注意点。 + +(1)短路机制 + +```javascript +a?.[++x] +// 等同于 +a == null ? undefined : a[++x] +``` -// 如果 a 是 null 或 undefined,下面的语句不产生任何效果 -// 否则执行 a.b = 42 -a?.b = 42 +上面代码中,如果`a`是`undefined`或`null`,那么`x`不会进行递增运算。也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。 -// 如果 a 是 null 或 undefined,下面的语句不产生任何效果 +(2)delete 运算符 + +```javascript delete a?.b +// 等同于 +a == null ? undefined : delete a.b +``` + +上面代码中,如果`a`是`undefined`或`null`,会直接返回`undefined`,而不会进行`delete`运算。 + +(3)报错场合 + +以下写法是禁止,会报错。 + +```javascript +// 构造函数判断 +new a?.() + +// 运算符右侧是模板字符串 +a?.`{b}` + +// 链判断运算符前后有构造函数或模板字符串 +new a?.b() +a?.b`{c}` + +// 链运算符用于赋值运算符左侧 +a?.b = c ``` +(4)右侧不得为十进制数值 + +为了保证兼容以前的代码,允许`foo?.3:0`被解析成`foo ? .3 : 0`,因此规定如果`?.`后面紧跟一个十进制数字,那么`?.`不再被看成是一个完整的运算符,而会按照三元运算符进行处理,也就是说,那个小数点会归属于后面的十进制数字,形成一个小数。 + ## 直接输入 U+2028 和 U+2029 JavaScript 字符串允许直接输入字符,以及输入字符的转义形式。举例来说,“中”的 Unicode 码点是 U+4e2d,你可以直接在字符串里面输入这个汉字,也可以输入它的转义形式`\u4e2d`,两者是等价的。 From 52e67f71da82dd4bee54bc38682ffacdf7e0024f Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 26 Feb 2018 15:20:30 +0800 Subject: [PATCH 007/492] docs(map): fix map #614 --- docs/set-map.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/set-map.md b/docs/set-map.md index 27f109e13..bcbd5370a 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -805,7 +805,7 @@ new Map([ **(3)Map 转为对象** -如果所有 Map 的键都是字符串,它可以转为对象。 +如果所有 Map 的键都是字符串,它可以无损地转为对象。 ```javascript function strMapToObj(strMap) { @@ -823,6 +823,8 @@ strMapToObj(myMap) // { yes: true, no: false } ``` +如果有非字符串的键名,那么这个键名会被转成字符串,再作为对象的键名。 + **(4)对象转为 Map** ```javascript From 50bd8d09d2fe27f747e848c0320c7ea78e1267a8 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 26 Feb 2018 15:22:47 +0800 Subject: [PATCH 008/492] docs(proxy): fix proxy #616 --- docs/proxy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proxy.md b/docs/proxy.md index e71e40d48..bacb8ac01 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -209,7 +209,7 @@ let arr = createArray('a', 'b', 'c'); arr[-1] // c ``` -上面代码中,数组的位置参数是`-1`,就会输出数组的倒数最后一个成员。 +上面代码中,数组的位置参数是`-1`,就会输出数组的倒数第一个成员。 利用 Proxy,可以将读取属性的操作(`get`),转变为执行某个函数,从而实现属性的链式操作。 From 69a86e75c54ae6a8cda20ff0c854f8c24ebc3324 Mon Sep 17 00:00:00 2001 From: xianshenglu Date: Tue, 27 Feb 2018 09:28:35 +0800 Subject: [PATCH 009/492] =?UTF-8?q?=E4=B8=A5=E8=B0=A8=E5=8C=96=20\S=20?= =?UTF-8?q?=E7=9A=84=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit \S 匹配所有非空白字符 而非所有不是空格的字符 --- docs/regex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/regex.md b/docs/regex.md index 6a78a708f..f64421b4c 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -105,7 +105,7 @@ ES6 新增了使用大括号表示 Unicode 字符,这种表示法在正则表 /^\S$/u.test('𠮷') // true ``` -上面代码的`\S`是预定义模式,匹配所有不是空格的字符。只有加了`u`修饰符,它才能正确匹配码点大于`0xFFFF`的 Unicode 字符。 +上面代码的`\S`是预定义模式,匹配所有非空白字符。只有加了`u`修饰符,它才能正确匹配码点大于`0xFFFF`的 Unicode 字符。 利用这一点,可以写出一个正确返回字符串长度的函数。 From 53389645e7790b0d5009d9e6fa32fe31246e56d6 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 1 Mar 2018 13:30:46 +0800 Subject: [PATCH 010/492] docs(promise): edit promise --- docs/promise.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/promise.md b/docs/promise.md index 4793c58b3..15b1ca780 100644 --- a/docs/promise.md +++ b/docs/promise.md @@ -681,8 +681,10 @@ const p = Promise.race([ setTimeout(() => reject(new Error('request timeout')), 5000) }) ]); -p.then(response => console.log(response)); -p.catch(error => console.log(error)); + +p +.then(console.log) +.catch(console.error); ``` 上面代码中,如果 5 秒之内`fetch`方法无法返回结果,变量`p`的状态就会变为`rejected`,从而触发`catch`方法指定的回调函数。 From b4f12261780c5f446fd12bbb3a42a3c95657b966 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Fri, 2 Mar 2018 12:42:37 +0800 Subject: [PATCH 011/492] docs(regex): edit regex --- docs/regex.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/regex.md b/docs/regex.md index 6a78a708f..8de7fc724 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -182,7 +182,7 @@ match.index // 3 REGEX.lastIndex // 4 // 4号位开始匹配失败 -REGEX.exec('xaxa') // null +REGEX.exec('xaya') // null ``` 上面代码中,`lastIndex`属性指定每次搜索的开始位置,`g`修饰符从这个位置开始向后搜索,直到发现匹配为止。 @@ -202,7 +202,7 @@ REGEX.exec('xaya') // null REGEX.lastIndex = 3; // 3号位置是粘连,匹配成功 -const match = REGEX.exec('xaxa'); +const match = REGEX.exec('xaya'); match.index // 3 REGEX.lastIndex // 4 ``` From 3c7e8a6365723ee7aa4e5ca67c4edb8c0cd4e5a4 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Fri, 2 Mar 2018 15:44:37 +0800 Subject: [PATCH 012/492] docs(module-extends): edit extends --- docs/class-extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 25d94e466..b65d11485 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -389,7 +389,7 @@ class B { // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); -// B 的实例继承 A 的静态属性 +// B 继承 A 的静态属性 Object.setPrototypeOf(B, A); const b = new B(); From 3d8af6149cf3d3f44fb03c1b126de142d8b451f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=A6=8F=E5=AE=97?= Date: Sat, 3 Mar 2018 20:35:02 +0800 Subject: [PATCH 013/492] =?UTF-8?q?=E7=BB=99=E5=BD=93=E5=89=8D=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E5=8A=A0=E4=B8=8A=E5=90=8C=E5=90=8D=E5=B1=9E=E4=BA=8E?= =?UTF-8?q?=EF=BC=8C=E5=BD=A2=E6=88=90=E5=AF=B9=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 给当前对象加上同名属于,由于值不同,会有更直观的对比~ 同时,也和最后一个例子有呼应,方便初学者理解 --- docs/object.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/object.md b/docs/object.md index c5249725a..d6ef05138 100644 --- a/docs/object.md +++ b/docs/object.md @@ -1032,6 +1032,7 @@ const proto = { }; const obj = { + foo: 'world', find() { return super.foo; } From fecda8655d4f31242a89fc69d9701a9445fa2c5c Mon Sep 17 00:00:00 2001 From: TinaC Date: Mon, 5 Mar 2018 10:26:07 +0800 Subject: [PATCH 014/492] fix typo --- docs/module-loader.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/module-loader.md b/docs/module-loader.md index 4e7f86df0..aa3b23edc 100644 --- a/docs/module-loader.md +++ b/docs/module-loader.md @@ -631,7 +631,7 @@ ReferenceError: foo is not defined 上面代码中,执行`a.mjs`以后会报错,`foo`变量未定义,这是为什么? -让我们一行行来看,ES6 循环加载是怎么处理的。首先,执行`a.mjs`以后,引擎发现它加载了`b.mjs`,因此会优先执行`b.mjs`,然后再执行`a.js`。接着,执行`b.mjs`的时候,已知它从`a.mjs`输入了`foo`接口,这时不会去执行`a.mjs`,而是认为这个接口已经存在了,继续往下执行。执行到第三行`console.log(foo)`的时候,才发现这个接口根本没定义,因此报错。 +让我们一行行来看,ES6 循环加载是怎么处理的。首先,执行`a.mjs`以后,引擎发现它加载了`b.mjs`,因此会优先执行`b.mjs`,然后再执行`a.mjs`。接着,执行`b.mjs`的时候,已知它从`a.mjs`输入了`foo`接口,这时不会去执行`a.mjs`,而是认为这个接口已经存在了,继续往下执行。执行到第三行`console.log(foo)`的时候,才发现这个接口根本没定义,因此报错。 解决这个问题的方法,就是让`b.mjs`运行的时候,`foo`已经有定义了。这可以通过将`foo`写成函数来解决。 From 3cf3f8fdb6548e66ee8c3234cd44234761ae5372 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 6 Mar 2018 12:12:55 +0800 Subject: [PATCH 015/492] =?UTF-8?q?docs(async):=20fix=20=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E9=81=8D=E5=8E=86=E5=99=A8=E5=87=BD=E6=95=B0=20#622?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/async.md | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/docs/async.md b/docs/async.md index d922b4197..481315200 100644 --- a/docs/async.md +++ b/docs/async.md @@ -733,10 +733,14 @@ console.log(v1, v2); // a b 另一种用法是一次性调用所有的`next`方法,然后`await`最后一步操作。 ```javascript -const writer = openFile('someFile.txt'); -writer.next('hello'); -writer.next('world'); -await writer.return(); +async function runner() { + const writer = openFile('someFile.txt'); + writer.next('hello'); + writer.next('world'); + await writer.return(); +} + +runner(); ``` ### for await...of @@ -836,7 +840,7 @@ async function* map(iterable, func) { } ``` -上面代码中,可以看到有了异步遍历器以后,同步 Generator 函数和异步 Generator 函数的写法基本上是一致的。 +上面代码中,`map`是一个 Generator 函数,第一个参数是可遍历对象`iterable`,第二个参数是一个回调函数`func`。`map`的作用是将`iterable`每一步返回的值,使用`func`进行处理。上面有两个版本的`map`,前一个处理同步遍历器,后一个处理异步遍历器,可以看到两个版本的写法基本上是一致的。 下面是另一个异步 Generator 函数的例子。 @@ -854,7 +858,7 @@ async function* readLines(path) { } ``` -上面代码中,异步操作前面使用`await`关键字标明,即`await`后面的操作,应该返回 Promise 对象。凡是使用`yield`关键字的地方,就是`next`方法的停下来的地方,它后面的表达式的值(即`await file.readLine()`的值),会作为`next()`返回对象的`value`属性,这一点是与同步 Generator 函数一致的。 +上面代码中,异步操作前面使用`await`关键字标明,即`await`后面的操作,应该返回 Promise 对象。凡是使用`yield`关键字的地方,就是`next`方法停下来的地方,它后面的表达式的值(即`await file.readLine()`的值),会作为`next()`返回对象的`value`属性,这一点是与同步 Generator 函数一致的。 异步 Generator 函数内部,能够同时使用`await`和`yield`命令。可以这样理解,`await`命令用于将外部操作产生的值输入函数内部,`yield`命令用于将函数内部的值输出。 @@ -881,42 +885,50 @@ async function* prefixLines(asyncIterable) { 异步 Generator 函数的返回值是一个异步 Iterator,即每次调用它的`next`方法,会返回一个 Promise 对象,也就是说,跟在`yield`命令后面的,应该是一个 Promise 对象。 ```javascript +function fetchRandom() { + const url = 'https://www.random.org/decimal-fractions/' + + '?num=1&dec=10&col=1&format=plain&rnd=new'; + return fetch(url); +} + async function* asyncGenerator() { console.log('Start'); - const result = await doSomethingAsync(); // (A) - yield 'Result: '+ result; // (B) + const result = await fetchRandom(); // (A) + yield 'Result: ' + await result.text(); // (B) console.log('Done'); } const ag = asyncGenerator(); -ag.next().then({value, done} => { - // ... +ag.next().then(({value, done}) => { + console.log(value); }) ``` -上面代码中,`ag`是`asyncGenerator`函数返回的异步 Iterator 对象。调用`ag.next()`以后,`asyncGenerator`函数内部的执行顺序如下。 +上面代码中,`ag`是`asyncGenerator`函数返回的异步遍历器对象。调用`ag.next()`以后,上面代码的执行顺序如下。 -1. 打印出`Start`。 -2. `await`命令返回一个 Promise 对象,但是程序不会停在这里,继续往下执行。 -3. 程序在`B`处暂停执行,`yield`命令立刻返回一个 Promise 对象,该对象就是`ag.next()`的返回值。 -4. `A`处`await`命令后面的那个 Promise 对象 resolved,产生的值放入`result`变量。 -5. `B`处的 Promise 对象 resolved,`then`方法指定的回调函数开始执行,该函数的参数是一个对象,`value`的值是表达式`'Result: ' + result`的值,`done`属性的值是`false`。 +1. `ag.next()`立刻返回一个 Promise 对象。 +1. `asyncGenerator`函数开始执行,打印出`Start`。 +1. `await`命令返回一个 Promise 对象,`asyncGenerator`函数停在这里。 +1. A 处变成 fulfilled 状态,产生的值放入`result`变量,`asyncGenerator`函数继续往下执行。 +1. 函数在 B 处的`yield`暂停执行,一旦`yield`命令取到值,`ag.next()`返回的那个 Promise 对象变成 fulfilled 状态。 +1. `ag.next()`后面的`then`方法指定的回调函数开始执行。该回调函数的参数是一个对象`{value, done}`,其中`value`的值是`yield`命令后面的那个表达式的值,`done`的值是`false`。 A 和 B 两行的作用类似于下面的代码。 ```javascript return new Promise((resolve, reject) => { - doSomethingAsync() + fetchRandom() + .then(result => result.text()) .then(result => { resolve({ - value: 'Result: '+result, + value: 'Result: ' + result, done: false, }); }); }); ``` -如果异步 Generator 函数抛出错误,会被 Promise 对象`reject`,然后抛出的错误被`catch`方法捕获。 +如果异步 Generator 函数抛出错误,会导致 Promise 对象的状态变为`reject`,然后抛出的错误被`catch`方法捕获。 ```javascript async function* asyncGenerator() { From c26d2a55e6d3d3249d07839038febfbe88a2bb11 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 10 Mar 2018 16:57:58 +0800 Subject: [PATCH 016/492] docs(set): fix bug #623 --- docs/set-map.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/set-map.md b/docs/set-map.md index bcbd5370a..9d930845b 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -34,21 +34,20 @@ const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]); items.size // 5 // 例三 -function divs () { - return [...document.querySelectorAll('div')]; -} - -const set = new Set(divs()); +const set = new Set(document.querySelectorAll('div')); set.size // 56 // 类似于 -divs().forEach(div => set.add(div)); +const set = new Set(); +document + .querySelectorAll('div') + .forEach(div => set.add(div)); set.size // 56 ``` 上面代码中,例一和例二都是`Set`函数接受数组作为参数,例三是接受类似数组的对象作为参数。 -上面代码中,也展示了一种去除数组重复成员的方法。 +上面代码也展示了一种去除数组重复成员的方法。 ```javascript // 去除数组的重复成员 From 59f8665131e1730255294c38148e21c3fef2fb4d Mon Sep 17 00:00:00 2001 From: Chiki Date: Mon, 12 Mar 2018 10:21:11 +0800 Subject: [PATCH 017/492] Update array.md --- docs/array.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/array.md b/docs/array.md index 0352bba64..30137c236 100644 --- a/docs/array.md +++ b/docs/array.md @@ -357,7 +357,7 @@ function foo() { } ``` -上面代码中,`querySelectorAll`方法返回的是一个类似数组的对象,可以将这个对象转为真正的数组,再使用`forEach`方法。 +上面代码中,`querySelectorAll`方法返回的是一个类似数组的对象,可以将这个对象转为真正的数组,再使用`filter`方法。 只要是部署了 Iterator 接口的数据结构,`Array.from`都能将其转为数组。 From a3a76e79e2e0362ae3fcd1220dc55ffda35fd61c Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 15 Mar 2018 14:32:21 +0800 Subject: [PATCH 018/492] docs(class-extends): fix super --- docs/class-extends.md | 6 +++--- docs/module-loader.md | 7 +++---- docs/module.md | 33 +++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index b65d11485..9026c6e71 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -231,7 +231,7 @@ let b = new B(); 上面代码中,属性`x`是定义在`A.prototype`上面的,所以`super.x`可以取到它的值。 -ES6 规定,通过`super`调用父类的方法时,方法内部的`this`指向子类。 +ES6 规定,通过`super`调用父类的方法时,方法内部的`this`指向当前的子类实例。 ```javascript class A { @@ -257,9 +257,9 @@ let b = new B(); b.m() // 2 ``` -上面代码中,`super.print()`虽然调用的是`A.prototype.print()`,但是`A.prototype.print()`内部的`this`指向子类`B`,导致输出的是`2`,而不是`1`。也就是说,实际上执行的是`super.print.call(this)`。 +上面代码中,`super.print()`虽然调用的是`A.prototype.print()`,但是`A.prototype.print()`内部的`this`指向子类`B`的实例,导致输出的是`2`,而不是`1`。也就是说,实际上执行的是`super.print.call(this)`。 -由于`this`指向子类,所以如果通过`super`对某个属性赋值,这时`super`就是`this`,赋值的属性会变成子类实例的属性。 +由于`this`指向子类实例,所以如果通过`super`对某个属性赋值,这时`super`就是`this`,赋值的属性会变成子类实例的属性。 ```javascript class A { diff --git a/docs/module-loader.md b/docs/module-loader.md index aa3b23edc..030c40c06 100644 --- a/docs/module-loader.md +++ b/docs/module-loader.md @@ -449,10 +449,9 @@ CommonJS 模块加载 ES6 模块,不能使用`require`命令,而要使用`im // es.mjs let foo = { bar: 'my-default' }; export default foo; -foo = null; // cjs.js -const es_namespace = await import('./es'); +const es_namespace = await import('./es.mjs'); // es_namespace = { // get default() { // ... @@ -462,7 +461,7 @@ console.log(es_namespace.default); // { bar:'my-default' } ``` -上面代码中,`default`接口变成了`es_namespace.default`属性。另外,由于存在缓存机制,`es.mjs`对`foo`的重新赋值没有在模块外部反映出来。 +上面代码中,`default`接口变成了`es_namespace.default`属性。 下面是另一个例子。 @@ -730,7 +729,7 @@ module.exports = function (n) { } ``` -上面代码中,`even.js`加载`odd.js`,而`odd.js`又去加载`even.js`,形成“循环加载”。这时,执行引擎就会输出`even.js`已经执行的部分(不存在任何结果),所以在`odd.js`之中,变量`even`等于`null`,等到后面调用`even(n-1)`就会报错。 +上面代码中,`even.js`加载`odd.js`,而`odd.js`又去加载`even.js`,形成“循环加载”。这时,执行引擎就会输出`even.js`已经执行的部分(不存在任何结果),所以在`odd.js`之中,变量`even`等于`null`,等到后面调用`even(n - 1)`就会报错。 ```bash $ node diff --git a/docs/module.md b/docs/module.md index 0a0f2a95e..c805248d2 100644 --- a/docs/module.md +++ b/docs/module.md @@ -650,7 +650,7 @@ import {db, users} from './index'; ### 简介 -前面介绍过,`import`命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适)。所以,下面的代码会报错。 +前面介绍过,`import`命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(`import`命令叫做”连接“ binding 其实更合适)。所以,下面的代码会报错。 ```javascript // 报错 @@ -668,7 +668,7 @@ const path = './' + fileName; const myModual = require(path); ``` -上面的语句就是动态加载,`require`到底加载哪一个模块,只有运行时才知道。`import`语句做不到这一点。 +上面的语句就是动态加载,`require`到底加载哪一个模块,只有运行时才知道。`import`命令做不到这一点。 因此,有一个[提案](https://github.com/tc39/proposal-dynamic-import),建议引入`import()`函数,完成动态加载。 @@ -692,9 +692,34 @@ import(`./section-modules/${someVariable}.js`) }); ``` -`import()`函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,也会加载指定的模块。另外,`import()`函数与所加载的模块没有静态连接关系,这点也是与`import`语句不相同。 +`import()`函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,`import()`函数与所加载的模块没有静态连接关系,这点也是与`import`语句不相同。 -`import()`类似于 Node 的`require`方法,区别主要是前者是异步加载,后者是同步加载。 +`import()`类似于 Node 的`require`方法,区别主要是前者是异步加载,后者是同步加载。`import()`的浏览器实现,类似于下面的写法。 + +```javascript +function importModule(url) { + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2); + script.type = "module"; + script.textContent = `import * as m from "${url}"; window.${tempGlobal} = m;`; + + script.onload = () => { + resolve(window[tempGlobal]); + delete window[tempGlobal]; + script.remove(); + }; + + script.onerror = () => { + reject(new Error("Failed to load module script with URL " + url)); + delete window[tempGlobal]; + script.remove(); + }; + + document.documentElement.appendChild(script); + }); +} +``` ### 适用场合 From 592ab333d8ba6753796106c6bd9018be768b4fb7 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sun, 25 Mar 2018 20:38:17 +0800 Subject: [PATCH 019/492] docs(object): fix object spread #630 --- docs/number.md | 2 +- docs/object.md | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/number.md b/docs/number.md index 478db3efd..32bf4b56b 100644 --- a/docs/number.md +++ b/docs/number.md @@ -62,7 +62,7 @@ Number.isNaN('true' / 0) // true Number.isNaN('true' / 'true') // true ``` -注意,如果参数类型不是数值,`Number.isNaN`一律返回`false`。 +如果参数类型不是`NaN`,`Number.isNaN`一律返回`false`。 它们与传统的全局方法`isFinite()`和`isNaN()`的区别在于,传统方法先调用`Number()`将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,`Number.isFinite()`对于非数值一律返回`false`, `Number.isNaN()`只有对于`NaN`才返回`true`,非`NaN`一律返回`false`。 diff --git a/docs/object.md b/docs/object.md index d6ef05138..b93b53513 100644 --- a/docs/object.md +++ b/docs/object.md @@ -1317,13 +1317,19 @@ o3.a // undefined const o = Object.create({ x: 1, y: 2 }); o.z = 3; -let { x, ...{ y, z } } = o; +let { x, ...newObj } = o; +let { y, z } = newObj; x // 1 y // undefined z // 3 ``` -上面代码中,变量`x`是单纯的解构赋值,所以可以读取对象`o`继承的属性;变量`y`和`z`是扩展运算符的解构赋值,只能读取对象`o`自身的属性,所以变量`z`可以赋值成功,变量`y`取不到值。 +上面代码中,变量`x`是单纯的解构赋值,所以可以读取对象`o`继承的属性;变量`y`和`z`是扩展运算符的解构赋值,只能读取对象`o`自身的属性,所以变量`z`可以赋值成功,变量`y`取不到值。ES6 规定,变量声明语句之中,如果使用解构赋值,扩展运算符后面必须是一个变量名,而不能是一个解构赋值表达式,所以上面代码引入了中间变量`newObj`,如果写成下面这样会报错。 + +```javascript +let { x, ...{ y, z } } = o; +// SyntaxError: ... must be followed by an identifier in declaration contexts +``` 解构赋值的一个用处,是扩展某个函数的参数,引入其他操作。 From 27784cd0cff223ea417ecbbf23e6f212d11c0af9 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 27 Mar 2018 19:07:42 +0800 Subject: [PATCH 020/492] docs(Proxy): edit Proxy --- docs/proxy.md | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/docs/proxy.md b/docs/proxy.md index bacb8ac01..7daf8afa4 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -145,7 +145,7 @@ fproxy.foo === "Hello, foo" // true ### get() -`get`方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(即`this`关键字指向的那个对象),其中最后一个参数可选。 +`get`方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。 `get`方法的用法,上文已经有一个例子,下面是另一个拦截读取操作的例子。 @@ -389,9 +389,45 @@ proxy.foo = 'bar'; proxy.foo === proxy // true ``` -上面代码中,`set`方法的第四个参数`receiver`,总是返回`this`关键字所指向的那个对象,即`proxy`实例本身。 +上面代码中,`set`方法的第四个参数`receiver`,指的是操作行为所在的那个对象,一般情况下是`proxy`实例本身,请看下面的例子。 -注意,如果目标对象自身的某个属性,不可写也不可配置,那么`set`不得改变这个属性的值,只能返回同样的值,否则报错。 +```javascript +const handler = { + set: function(obj, prop, value, receiver) { + obj[prop] = receiver; + } +}; +const proxy = new Proxy({}, handler); +const myObj = {}; +Object.setPrototypeOf(myObj, proxy); + +myObj.foo = 'bar'; +myObj.foo === myObj // true +``` + +上面代码中,设置`myObj.foo`属性的值时,`myObj`并没有`foo`属性,因此引擎会到`myObj`的原型链去找`foo`属性。`myObj`的原型对象`proxy`是一个 Proxy 实例,设置它的`foo`属性会触发`set`方法。这时,第四个参数`receiver`就指向原始赋值行为所在的对象`myObj`。 + +注意,如果目标对象自身的某个属性,不可写或不可配置,那么`set`方法将不起作用。 + +```javascript +const obj = {}; +Object.defineProperty(obj, 'foo', { + value: 'bar', + writable: false, +}); + +const handler = { + set: function(obj, prop, value, receiver) { + obj[prop] = 'baz'; + } +}; + +const proxy = new Proxy(obj, handler); +proxy.foo = 'baz'; +proxy.foo // "bar" +``` + +上面代码中,`obj.foo`属性不可写,Proxy 对这个属性的`set`代理将不会生效。 ### apply() From 9b3d8c9afe91e485b50f01ac94f5cbbe5f61ba0f Mon Sep 17 00:00:00 2001 From: Jim Ma Date: Thu, 29 Mar 2018 12:10:52 +0800 Subject: [PATCH 021/492] add SUMMARY.md for gitbook support --- SUMMARY.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 SUMMARY.md diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 000000000..28dec1cc5 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,31 @@ +# Summary + +* [0. 前言](README.md) +* [1. ECMAScript 6简介](docs/intro.md) +* [2. let 和 const 命令](docs/let.md) +* [3. 变量的解构赋值](docs/destructuring.md) +* [4. 字符串的扩展](docs/string.md) +* [5. 正则的扩展](docs/regex.md) +* [6. 数值的扩展](docs/number.md) +* [7. 函数的扩展](docs/function.md) +* [8. 数组的扩展](docs/array.md) +* [9. 对象的扩展](docs/object.md) +* [10. Symbol](docs/symbol.md) +* [11. Set 和 Map 数据结构](docs/set-map.md) +* [12. Proxy](docs/proxy.md) +* [13. Reflect](docs/reflect.md) +* [14. Promise 对象](docs/promise.md) +* [15. Iterator 和 for...of 循环](docs/iterator.md) +* [16. Generator 函数的语法](docs/generator.md) +* [17. Generator 函数的异步应用](docs/generator-async.md) +* [18. async 函数](docs/async.md) +* [19. Class 的基本语法](docs/class.md) +* [20. Class 的继承](docs/class-extends.md) +* [21. Decorator](docs/decorator.md) +* [22. Module 的语法](docs/module.md) +* [23. Module 的加载实现](docs/module-loader.md) +* [24. 编程风格](docs/style.md) +* [25. 读懂规格](docs/spec.md) +* [26. ArrayBuffer](docs/arraybuffer.md) +* [27. 最新提案](docs/proposals.md) +* [28. 参考链接](docs/reference.md) \ No newline at end of file From 02631361e1b664506688f3be5ff7cde590e5c460 Mon Sep 17 00:00:00 2001 From: Jim Ma Date: Thu, 29 Mar 2018 12:22:51 +0800 Subject: [PATCH 022/492] add cover for gitbook --- cover.jpg | 1 + cover_small.jpg | 1 + 2 files changed, 2 insertions(+) create mode 120000 cover.jpg create mode 120000 cover_small.jpg diff --git a/cover.jpg b/cover.jpg new file mode 120000 index 000000000..0fa7635c3 --- /dev/null +++ b/cover.jpg @@ -0,0 +1 @@ +images/cover-3rd.jpg \ No newline at end of file diff --git a/cover_small.jpg b/cover_small.jpg new file mode 120000 index 000000000..61091a8ce --- /dev/null +++ b/cover_small.jpg @@ -0,0 +1 @@ +images/cover_thumbnail_3rd.jpg \ No newline at end of file From f7c8e8800afe8c36d1d0c194cf70f033a2ccb43a Mon Sep 17 00:00:00 2001 From: Jim Ma Date: Thu, 29 Mar 2018 13:09:35 +0800 Subject: [PATCH 023/492] add book.json for gitbook --- book.json | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 book.json diff --git a/book.json b/book.json new file mode 100644 index 000000000..be5d775bd --- /dev/null +++ b/book.json @@ -0,0 +1,36 @@ +{ + "author": "阮一峰", + "description": "《ECMAScript 6 入门》是一本开源的 JavaScript 语言教程,全面介绍 ECMAScript 6 新引入的语法特性。", + "extension": null, + "generator": "site", + "isbn": "9787121324758", + "links": { + "sharing": { + "all": null, + "facebook": null, + "google": null, + "twitter": null, + "weibo": null + }, + "sidebar": { + "阮一峰的个人网站": "http://www.ruanyifeng.com/blog/" + } + }, + "output": null, + "pdf": { + "fontSize": 12, + "footerTemplate": null, + "headerTemplate": null, + "margin": { + "bottom": 36, + "left": 62, + "right": 62, + "top": 36 + }, + "pageNumbers": false, + "paperSize": "a4" + }, + "plugins": [], + "title": "ECMAScript 6 入门", + "variables": {} +} \ No newline at end of file From 9e86918b4a87d6840679bdafb92ac67ace6ec591 Mon Sep 17 00:00:00 2001 From: xianshenglu Date: Sat, 31 Mar 2018 11:21:26 +0800 Subject: [PATCH 024/492] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=B8=8B=E8=A1=A8?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原表述可能有误导,完善了下 --- docs/async.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/async.md b/docs/async.md index 481315200..4624126e1 100644 --- a/docs/async.md +++ b/docs/async.md @@ -757,7 +757,7 @@ async function f() { // b ``` -上面代码中,`createAsyncIterable()`返回一个异步遍历器,`for...of`循环自动调用这个遍历器的`next`方法,会得到一个 Promise 对象。`await`用来处理这个 Promise 对象,一旦`resolve`,就把得到的值(`x`)传入`for...of`的循环体。 +上面代码中,`createAsyncIterable()`返回一个拥有异步遍历器的对象,`for...of`循环自动调用这个对象的异步遍历器的`next`方法,会得到一个 Promise 对象。`await`用来处理这个 Promise 对象,一旦`resolve`,就把得到的值(`x`)传入`for...of`的循环体。 `for await...of`循环的一个用途,是部署了 asyncIterable 操作的异步接口,可以直接放入这个循环。 From 7fc640d46b949e1809538a0e28dbf966b18bf7c8 Mon Sep 17 00:00:00 2001 From: xianshenglu Date: Sun, 1 Apr 2018 21:23:14 +0800 Subject: [PATCH 025/492] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=A1=A8=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/class-extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 9026c6e71..7a6022e1d 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -231,7 +231,7 @@ let b = new B(); 上面代码中,属性`x`是定义在`A.prototype`上面的,所以`super.x`可以取到它的值。 -ES6 规定,通过`super`调用父类的方法时,方法内部的`this`指向当前的子类实例。 +ES6 规定,在子类普通方法中通过`super`调用父类的方法(此时调用的是父类普通方法,因为`super`指向父类的原型对象)时,方法内部的`this`指向当前的子类实例;在子类静态方法中通过`super`调用父类的方法(此时调用的是父类静态方法,因为`super`指向父类)时,方法内部的`this`指向当前的子类; ```javascript class A { From 36fc72005778ef1f83357b2b630731d6f03a2066 Mon Sep 17 00:00:00 2001 From: xianshenglu Date: Sun, 1 Apr 2018 21:26:00 +0800 Subject: [PATCH 026/492] =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=A1=A8=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/class-extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 9026c6e71..56991bfbe 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -342,7 +342,7 @@ class B extends A { let b = new B(); ``` -上面代码中,`super.valueOf()`表明`super`是一个对象,因此就不会报错。同时,由于`super`使得`this`指向`B`,所以`super.valueOf()`返回的是一个`B`的实例。 +上面代码中,`super.valueOf()`表明`super`是一个对象,因此就不会报错。同时,由于`super`使得`this`指向`B`的实例,所以`super.valueOf()`返回的是一个`B`的实例。 最后,由于对象总是继承其他对象的,所以可以在任意一个对象中,使用`super`关键字。 From 5e2ed331aa2b8599907c6d2f35a254a8be382cd6 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 3 Apr 2018 18:35:59 +0800 Subject: [PATCH 027/492] docs(class-extends): edit class-extends --- docs/async.md | 2 +- docs/class-extends.md | 30 +++++++++++++++++++++++++++++- docs/regex.md | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/async.md b/docs/async.md index 4624126e1..64d1ac1f7 100644 --- a/docs/async.md +++ b/docs/async.md @@ -757,7 +757,7 @@ async function f() { // b ``` -上面代码中,`createAsyncIterable()`返回一个拥有异步遍历器的对象,`for...of`循环自动调用这个对象的异步遍历器的`next`方法,会得到一个 Promise 对象。`await`用来处理这个 Promise 对象,一旦`resolve`,就把得到的值(`x`)传入`for...of`的循环体。 +上面代码中,`createAsyncIterable()`返回一个拥有异步遍历器接口的对象,`for...of`循环自动调用这个对象的异步遍历器的`next`方法,会得到一个 Promise 对象。`await`用来处理这个 Promise 对象,一旦`resolve`,就把得到的值(`x`)传入`for...of`的循环体。 `for await...of`循环的一个用途,是部署了 asyncIterable 操作的异步接口,可以直接放入这个循环。 diff --git a/docs/class-extends.md b/docs/class-extends.md index 7a6022e1d..15cb0a636 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -231,7 +231,7 @@ let b = new B(); 上面代码中,属性`x`是定义在`A.prototype`上面的,所以`super.x`可以取到它的值。 -ES6 规定,在子类普通方法中通过`super`调用父类的方法(此时调用的是父类普通方法,因为`super`指向父类的原型对象)时,方法内部的`this`指向当前的子类实例;在子类静态方法中通过`super`调用父类的方法(此时调用的是父类静态方法,因为`super`指向父类)时,方法内部的`this`指向当前的子类; +ES6 规定,在子类普通方法中通过`super`调用父类的方法时,方法内部的`this`指向当前的子类实例。 ```javascript class A { @@ -314,6 +314,34 @@ child.myMethod(2); // instance 2 上面代码中,`super`在静态方法之中指向父类,在普通方法之中指向父类的原型对象。 +另外,在子类的静态方法中通过`super`调用父类的方法时,方法内部的`this`指向当前的子类,而不是子类的实例。 + +```javascript +class A { + constructor() { + this.x = 1; + } + static print() { + console.log(this.x); + } +} + +class B extends A { + constructor() { + super(); + this.x = 2; + } + static m() { + super.print(); + } +} + +B.x = 3; +B.m() // 3 +``` + +上面代码中,静态方法`B.m`里面,`super.print`指向父类的静态方法。这个方法里面的`this`指向的是`B`,而不是`B`的实例。 + 注意,使用`super`的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。 ```javascript diff --git a/docs/regex.md b/docs/regex.md index cf45072d4..4ee07ed01 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -368,7 +368,7 @@ const RE_DOLLAR_PREFIX = /(?<=\$)foo/g; “后行断言”的实现,需要先匹配`/(?<=y)x/`的`x`,然后再回到左边,匹配`y`的部分。这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。 -首先,”后行断言“的组匹配,与正常情况下结果是不一样的。 +首先,后行断言的组匹配,与正常情况下结果是不一样的。 ```javascript /(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"] From 536d2c408c0e70b7a57a3c7da5592ce01eb1cf02 Mon Sep 17 00:00:00 2001 From: Lemon_zhang <897418436@qq.com> Date: Wed, 4 Apr 2018 11:29:25 +0800 Subject: [PATCH 028/492] Update destructuring.md --- docs/destructuring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/destructuring.md b/docs/destructuring.md index 5f69ec7e3..fcb5e1437 100644 --- a/docs/destructuring.md +++ b/docs/destructuring.md @@ -630,7 +630,7 @@ jQuery.ajax = function (url, { crossDomain = false, global = true, // ... more config -}) { +} = {}) { // ... do stuff }; ``` From 013f7370fd0dc9e2fa363e025a556ad5c33bd95d Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 5 Apr 2018 13:50:18 +0800 Subject: [PATCH 029/492] doc(function): edit arrow function --- docs/function.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/function.md b/docs/function.md index 5969a84e0..208ca3970 100644 --- a/docs/function.md +++ b/docs/function.md @@ -594,12 +594,9 @@ ES6 允许使用“箭头”(`=>`)定义函数。 ```javascript var f = v => v; -``` - -上面的箭头函数等同于: -```javascript -var f = function(v) { +// 等同于 +var f = function (v) { return v; }; ``` @@ -634,6 +631,15 @@ let getTempItem = id => { id: id, name: "Temp" }; let getTempItem = id => ({ id: id, name: "Temp" }); ``` +下面是一种特殊情况,虽然可以运行,但会得到错误的结果。 + +```javascript +let foo = () => { a: 1 }; +foo() // undefined +``` + +上面代码中,原始意图是返回一个对象`{ a: 1 }`,但是由于引擎认为大括号是代码块,所以执行了一行语句`a: 1`。这时,`a`可以被解释为语句的标签,因此实际执行的语句是`1;`,然后函数就结束了,没有返回值。 + 如果箭头函数只有一行语句,且不需要返回值,可以采用下面的写法,就不用写大括号了。 ```javascript From 2eccfb5a3508091aba9b1989c7121ce97b7302e1 Mon Sep 17 00:00:00 2001 From: xianshenglu Date: Thu, 5 Apr 2018 18:27:56 +0800 Subject: [PATCH 030/492] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E6=95=88?= =?UTF-8?q?=E5=AD=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/spec.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 8a375cfcf..0374a769c 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -127,15 +127,15 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > Return the result of performing Strict Equality Comparison `x === y`. > 1. If `x` is `null` and `y` is `undefined`, return `true`. > 1. If `x` is `undefined` and `y` is `null`, return `true`. -> 1. If `Type(x)` is Number and `Type(y)` is String,\ +> 1. If `Type(x)` is Number and `Type(y)` is String, > return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is String and `Type(y)` is Number,\ +> 1. If `Type(x)` is String and `Type(y)` is Number, > return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(x)` is Boolean, return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(y)` is Boolean, return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then\ +> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then > return the result of the comparison `x == ToPrimitive(y)`. -> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then\ +> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then > return the result of the comparison `ToPrimitive(x) == y`. > 1. Return `false`. From 5d16ab071f8cf51ecb9fbda0af9facf24b2151e6 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 9 Apr 2018 10:47:22 +0800 Subject: [PATCH 031/492] docs(module): edit import() --- docs/module.md | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/docs/module.md b/docs/module.md index c805248d2..4fc5085ef 100644 --- a/docs/module.md +++ b/docs/module.md @@ -692,34 +692,7 @@ import(`./section-modules/${someVariable}.js`) }); ``` -`import()`函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,`import()`函数与所加载的模块没有静态连接关系,这点也是与`import`语句不相同。 - -`import()`类似于 Node 的`require`方法,区别主要是前者是异步加载,后者是同步加载。`import()`的浏览器实现,类似于下面的写法。 - -```javascript -function importModule(url) { - return new Promise((resolve, reject) => { - const script = document.createElement("script"); - const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2); - script.type = "module"; - script.textContent = `import * as m from "${url}"; window.${tempGlobal} = m;`; - - script.onload = () => { - resolve(window[tempGlobal]); - delete window[tempGlobal]; - script.remove(); - }; - - script.onerror = () => { - reject(new Error("Failed to load module script with URL " + url)); - delete window[tempGlobal]; - script.remove(); - }; - - document.documentElement.appendChild(script); - }); -} -``` +`import()`函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,`import()`函数与所加载的模块没有静态连接关系,这点也是与`import`语句不相同。`import()`类似于 Node 的`require`方法,区别主要是前者是异步加载,后者是同步加载。 ### 适用场合 From 2416e5685bfba66913da708fcf1bfd6f0d60ed2a Mon Sep 17 00:00:00 2001 From: GJ Wang Date: Mon, 9 Apr 2018 22:52:56 +0800 Subject: [PATCH 032/492] Update promise.md shouldn't use cooma. --- docs/promise.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/promise.md b/docs/promise.md index 15b1ca780..83afb2d08 100644 --- a/docs/promise.md +++ b/docs/promise.md @@ -484,7 +484,7 @@ someAsyncThing().then(function() { // carry on [ReferenceError: y is not defined] ``` -上面代码中,第二个`catch`方法用来捕获,前一个`catch`方法抛出的错误。 +上面代码中,第二个`catch`方法用来捕获前一个`catch`方法抛出的错误。 ## Promise.prototype.finally() From caeb8706bd66ab490ca01087081752d6bfc24acf Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sun, 15 Apr 2018 21:31:19 +0800 Subject: [PATCH 033/492] docs(decorator): edit decorator --- docs/decorator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decorator.md b/docs/decorator.md index 52dffceb3..3cc385fbf 100644 --- a/docs/decorator.md +++ b/docs/decorator.md @@ -201,7 +201,7 @@ function log(target, name, descriptor) { descriptor.value = function() { console.log(`Calling ${name} with`, arguments); - return oldValue.apply(null, arguments); + return oldValue.apply(this, arguments); }; return descriptor; From 7fab96c932f93e3671f736eafc2b3db3b9088d65 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 17 Apr 2018 15:53:05 +0800 Subject: [PATCH 034/492] =?UTF-8?q?docs(async):=20=E5=A2=9E=E5=8A=A0=20Str?= =?UTF-8?q?eam=20=E5=BC=82=E6=AD=A5=E9=81=8D=E5=8E=86=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E4=BE=8B=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/async.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/async.md b/docs/async.md index 64d1ac1f7..0a12272d2 100644 --- a/docs/async.md +++ b/docs/async.md @@ -799,6 +799,37 @@ async function () { // b ``` +Node v10 支持异步遍历器,Stream 就部署了这个接口。下面是读取文件的传统写法与异步遍历器写法的差异。 + +```javascript +// 传统写法 +function main(inputFilePath) { + const readStream = fs.createReadStream( + inputFilePath, + { encoding: 'utf8', highWaterMark: 1024 } + ); + readStream.on('data', (chunk) => { + console.log('>>> '+chunk); + }); + readStream.on('end', () => { + console.log('### DONE ###'); + }); +} + +// 异步遍历器写法 +async function main(inputFilePath) { + const readStream = fs.createReadStream( + inputFilePath, + { encoding: 'utf8', highWaterMark: 1024 } + ); + + for await (const chunk of readStream) { + console.log('>>> '+chunk); + } + console.log('### DONE ###'); +} +``` + ### 异步 Generator 函数 就像 Generator 函数返回一个同步遍历器对象一样,异步 Generator 函数的作用,是返回一个异步遍历器对象。 From b48a35bebbd7d6ad429e7dea351a0ca3da0d0111 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 18 Apr 2018 15:34:42 +0800 Subject: [PATCH 035/492] docs(proxy): edit proxy.ownkeys --- docs/proxy.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/proxy.md b/docs/proxy.md index 7daf8afa4..2f602b848 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -129,7 +129,7 @@ fproxy.foo === "Hello, foo" // true - **set(target, propKey, value, receiver)**:拦截对象属性的设置,比如`proxy.foo = v`或`proxy['foo'] = v`,返回一个布尔值。 - **has(target, propKey)**:拦截`propKey in proxy`的操作,返回一个布尔值。 - **deleteProperty(target, propKey)**:拦截`delete proxy[propKey]`的操作,返回一个布尔值。 -- **ownKeys(target)**:拦截`Object.getOwnPropertyNames(proxy)`、`Object.getOwnPropertySymbols(proxy)`、`Object.keys(proxy)`,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而`Object.keys()`的返回结果仅包括目标对象自身的可遍历属性。 +- **ownKeys(target)**:拦截`Object.getOwnPropertyNames(proxy)`、`Object.getOwnPropertySymbols(proxy)`、`Object.keys(proxy)`、`for...in`循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而`Object.keys()`的返回结果仅包括目标对象自身的可遍历属性。 - **getOwnPropertyDescriptor(target, propKey)**:拦截`Object.getOwnPropertyDescriptor(proxy, propKey)`,返回属性的描述对象。 - **defineProperty(target, propKey, propDesc)**:拦截`Object.defineProperty(proxy, propKey, propDesc)`、`Object.defineProperties(proxy, propDescs)`,返回一个布尔值。 - **preventExtensions(target)**:拦截`Object.preventExtensions(proxy)`,返回一个布尔值。 @@ -756,6 +756,7 @@ Object.isExtensible(p) // 报错 - `Object.getOwnPropertyNames()` - `Object.getOwnPropertySymbols()` - `Object.keys()` +- `for...in`循环 下面是拦截`Object.keys()`的例子。 @@ -850,6 +851,23 @@ Object.getOwnPropertyNames(p) // [ 'a', 'b', 'c' ] ``` +`for...in`循环也受到`ownKeys`方法的拦截。 + +```javascript +const obj = { hello: 'world' }; +const proxy = new Proxy(obj, { + ownKeys: function () { + return ['a', 'b']; + } +}); + +for (let key in proxy) { + console.log(key); // 没有任何输出 +} +``` + +上面代码中,`ownkeys`指定只返回`a`和`b`属性,由于`obj`没有这两个属性,因此`for...in`循环不会有任何输出。 + `ownKeys`方法返回的数组成员,只能是字符串或 Symbol 值。如果有其他类型的值,或者返回的根本不是数组,就会报错。 ```javascript From da319a110feb23eeb2c008d8fbde180149946430 Mon Sep 17 00:00:00 2001 From: KinFeng Date: Tue, 24 Apr 2018 15:53:28 +0800 Subject: [PATCH 036/492] =?UTF-8?q?fs=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=BA=94?= =?UTF-8?q?=E8=AF=A5=E6=98=AFreadFile=EF=BC=8C'f'=E6=94=B9=E6=88=90?= =?UTF-8?q?=E5=A4=A7=E5=86=99'F'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/module-loader.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/module-loader.md b/docs/module-loader.md index 030c40c06..a5ee61500 100644 --- a/docs/module-loader.md +++ b/docs/module-loader.md @@ -426,10 +426,10 @@ setTimeout(_ => module.exports = null); ```javascript // 不正确 -import { readfile } from 'fs'; +import { readFile } from 'fs'; ``` -上面的写法不正确,因为`fs`是 CommonJS 格式,只有在运行时才能确定`readfile`接口,而`import`命令要求编译时就确定这个接口。解决方法就是改为整体输入。 +上面的写法不正确,因为`fs`是 CommonJS 格式,只有在运行时才能确定`readFile`接口,而`import`命令要求编译时就确定这个接口。解决方法就是改为整体输入。 ```javascript // 正确的写法一 From 3226888ad87e3447407ce7941c2ea528fc6e5f61 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 25 Apr 2018 17:39:57 +0800 Subject: [PATCH 037/492] docs(acknowledgement): edit acknowledgement --- docs/acknowledgment.md | 5 +++++ docs/generator.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 docs/acknowledgment.md diff --git a/docs/acknowledgment.md b/docs/acknowledgment.md new file mode 100644 index 000000000..818faab9f --- /dev/null +++ b/docs/acknowledgment.md @@ -0,0 +1,5 @@ +# 鸣谢 + +## Generator + +网友 vision57 提出,`next()`、`throw()`、`return()`这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换`yield`表达式。 diff --git a/docs/generator.md b/docs/generator.md index 56f14e643..fde9a9816 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -708,7 +708,7 @@ g.next() // { value: 7, done: true } ## next()、throw()、return() 的共同点 -网友 vision57 提出,`next()`、`throw()`、`return()`这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换`yield`表达式。 +`next()`、`throw()`、`return()`这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换`yield`表达式。 `next()`是将`yield`表达式替换成一个值。 From 6fc5573b229e756001dfa8aa21e532bd03e7fdf8 Mon Sep 17 00:00:00 2001 From: wuzhiyu5 Date: Sat, 28 Apr 2018 13:57:38 +0800 Subject: [PATCH 038/492] =?UTF-8?q?=E4=BF=AE=E5=A4=8Des6=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E7=AB=A0=E8=8A=82=E9=93=BE=E6=8E=A5=E5=92=8C=E4=BC=AA=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/spec.md | 70 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 0374a769c..3d0cea915 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -111,7 +111,7 @@ ES6 规格将这个标准流程,使用简写的方式表达。 0 == null ``` -如果你不确定答案,或者想知道语言内部怎么处理,就可以去查看规格,[7.2.12 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-7.2.12)是对相等运算符(`==`)的描述。 +如果你不确定答案,或者想知道语言内部怎么处理,就可以去查看规格,[7.2.12 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-abstract-equality-comparison)是对相等运算符(`==`)的描述。 规格对每一种语法行为的描述,都分成两部分:先是总体的行为描述,然后是实现的算法细节。相等运算符的总体描述,只有一句话。 @@ -123,19 +123,19 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > 1. ReturnIfAbrupt(x). > 1. ReturnIfAbrupt(y). -> 1. If `Type(x)` is the same as `Type(y)`, then\ -> Return the result of performing Strict Equality Comparison `x === y`. +> 1. If `Type(x)` is the same as `Type(y)`, then +> 1. Return the result of performing Strict Equality Comparison `x === y`. > 1. If `x` is `null` and `y` is `undefined`, return `true`. > 1. If `x` is `undefined` and `y` is `null`, return `true`. -> 1. If `Type(x)` is Number and `Type(y)` is String, +> 1. If `Type(x)` is Number and `Type(y)` is String,
> return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is String and `Type(y)` is Number, +> 1. If `Type(x)` is String and `Type(y)` is Number,
> return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(x)` is Boolean, return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(y)` is Boolean, return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then +> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then
> return the result of the comparison `x == ToPrimitive(y)`. -> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then +> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then
> return the result of the comparison `ToPrimitive(x) == y`. > 1. Return `false`. @@ -154,7 +154,7 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > 1. 如果`Type(x)`是对象,`Type(y)`是字符串或数值或`Symbol`值,返回`ToPrimitive(x) == y`的结果。 > 1. 返回`false`。 -由于`0`的类型是数值,`null`的类型是 Null(这是规格[4.3.13 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-4.3.13)的规定,是内部 Type 运算的结果,跟`typeof`运算符无关)。因此上面的前 11 步都得不到结果,要到第 12 步才能得到`false`。 +由于`0`的类型是数值,`null`的类型是 Null(这是规格[4.3.13 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-null-type)的规定,是内部 Type 运算的结果,跟`typeof`运算符无关)。因此上面的前 11 步都得不到结果,要到第 12 步才能得到`false`。 ```javascript 0 == null // false @@ -199,7 +199,7 @@ a2.map(n => 1) // [, , ,] 为什么`a1`与`a2`成员的行为不一致?数组的成员是`undefined`或空位,到底有什么不同? -规格的[12.2.5 小节《数组的初始化》](http://www.ecma-international.org/ecma-262/6.0/#sec-12.2.5)给出了答案。 +规格的[12.2.5 小节《数组的初始化》](http://www.ecma-international.org/ecma-262/6.0/#sec-array-initializer)给出了答案。 > “Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array.” @@ -215,7 +215,7 @@ a2.map(n => 1) // [, , ,] ## 数组的 map 方法 -规格的[22.1.3.15 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-22.1.3.15)定义了数组的`map`方法。该小节先是总体描述`map`方法的行为,里面没有提到数组空位。 +规格的[22.1.3.15 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.map)定义了数组的`map`方法。该小节先是总体描述`map`方法的行为,里面没有提到数组空位。 后面的算法描述是这样的。 @@ -228,18 +228,18 @@ a2.map(n => 1) // [, , ,] > 1. Let `A` be `ArraySpeciesCreate(O, len)`. > 1. `ReturnIfAbrupt(A)`. > 1. Let `k` be 0. -> 1. Repeat, while `k` < `len`\ -> a. Let `Pk` be `ToString(k)`.\ -> b. Let `kPresent` be `HasProperty(O, Pk)`.\ -> c. `ReturnIfAbrupt(kPresent)`.\ -> d. If `kPresent` is `true`, then\ -> d-1. Let `kValue` be `Get(O, Pk)`.\ -> d-2. `ReturnIfAbrupt(kValue)`.\ -> d-3. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`.\ -> d-4. `ReturnIfAbrupt(mappedValue)`.\ -> d-5. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`.\ -> d-6. `ReturnIfAbrupt(status)`.\ -> e. Increase `k` by 1. +> 1. Repeat, while `k` < `len` +> 1. Let `Pk` be `ToString(k)`. +> 1. Let `kPresent` be `HasProperty(O, Pk)`. +> 1. `ReturnIfAbrupt(kPresent)`. +> 1. If `kPresent` is `true`, then +> 1. Let `kValue` be `Get(O, Pk)`. +> 1. `ReturnIfAbrupt(kValue)`. +> 1. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`. +> 1. `ReturnIfAbrupt(mappedValue)`. +> 1. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`. +> 1. `ReturnIfAbrupt(status)`. +> 1. Increase `k` by 1. > 1. Return `A`. 翻译如下。 @@ -253,21 +253,21 @@ a2.map(n => 1) // [, , ,] > 1. 生成一个新的数组`A`,跟当前数组的`length`属性保持一致 > 1. 如果报错就返回 > 1. 设定`k`等于 0 -> 1. 只要`k`小于当前数组的`length`属性,就重复下面步骤\ -> a. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串\ -> b. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性\ -> c. 如果报错就返回\ -> d. 如果`kPresent`等于`true`,则进行下面步骤\ -> d-1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性\ -> d-2. 如果报错就返回\ -> d-3. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数\ -> d-4. 如果报错就返回\ -> d-5. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置\ -> d-6. 如果报错就返回\ -> e. `k`增加 1 +> 1. 只要`k`小于当前数组的`length`属性,就重复下面步骤 +> 1. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串 +> 1. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性 +> 1. 如果报错就返回 +> 1. 如果`kPresent`等于`true`,则进行下面步骤 +> 1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性 +> 1. 如果报错就返回 +> 1. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数 +> 1. 如果报错就返回 +> 1. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置 +> 1. 如果报错就返回 +> 1. `k`增加 1 > 1. 返回`A` -仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 b 时,`kpresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 +仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 ii 时,`kPresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 ```javascript const arr = [, , ,]; From 86a012fafd22f09dfe07eaf28d8c8e37cb11ee17 Mon Sep 17 00:00:00 2001 From: wuzhiyu5 Date: Sat, 28 Apr 2018 15:14:33 +0800 Subject: [PATCH 039/492] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E4=BB=A5=E7=AC=A6=E5=90=88=E4=BC=AA=E4=BB=A3=E7=A0=81=E4=B8=AD?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/spec.md | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 3d0cea915..a7005870d 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -124,18 +124,18 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > 1. ReturnIfAbrupt(x). > 1. ReturnIfAbrupt(y). > 1. If `Type(x)` is the same as `Type(y)`, then -> 1. Return the result of performing Strict Equality Comparison `x === y`. +> 1. Return the result of performing Strict Equality Comparison `x === y`. > 1. If `x` is `null` and `y` is `undefined`, return `true`. > 1. If `x` is `undefined` and `y` is `null`, return `true`. -> 1. If `Type(x)` is Number and `Type(y)` is String,
+> 1. If `Type(x)` is Number and `Type(y)` is String, > return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is String and `Type(y)` is Number,
+> 1. If `Type(x)` is String and `Type(y)` is Number, > return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(x)` is Boolean, return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(y)` is Boolean, return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then
+> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then > return the result of the comparison `x == ToPrimitive(y)`. -> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then
+> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then > return the result of the comparison `ToPrimitive(x) == y`. > 1. Return `false`. @@ -229,17 +229,17 @@ a2.map(n => 1) // [, , ,] > 1. `ReturnIfAbrupt(A)`. > 1. Let `k` be 0. > 1. Repeat, while `k` < `len` -> 1. Let `Pk` be `ToString(k)`. -> 1. Let `kPresent` be `HasProperty(O, Pk)`. -> 1. `ReturnIfAbrupt(kPresent)`. -> 1. If `kPresent` is `true`, then -> 1. Let `kValue` be `Get(O, Pk)`. -> 1. `ReturnIfAbrupt(kValue)`. -> 1. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`. -> 1. `ReturnIfAbrupt(mappedValue)`. -> 1. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`. -> 1. `ReturnIfAbrupt(status)`. -> 1. Increase `k` by 1. +> 1. Let `Pk` be `ToString(k)`. +> 1. Let `kPresent` be `HasProperty(O, Pk)`. +> 1. `ReturnIfAbrupt(kPresent)`. +> 1. If `kPresent` is `true`, then +> 1. Let `kValue` be `Get(O, Pk)`. +> 1. `ReturnIfAbrupt(kValue)`. +> 1. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`. +> 1. `ReturnIfAbrupt(mappedValue)`. +> 1. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`. +> 1. `ReturnIfAbrupt(status)`. +> 1. Increase `k` by 1. > 1. Return `A`. 翻译如下。 @@ -254,20 +254,20 @@ a2.map(n => 1) // [, , ,] > 1. 如果报错就返回 > 1. 设定`k`等于 0 > 1. 只要`k`小于当前数组的`length`属性,就重复下面步骤 -> 1. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串 -> 1. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性 -> 1. 如果报错就返回 -> 1. 如果`kPresent`等于`true`,则进行下面步骤 -> 1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性 -> 1. 如果报错就返回 -> 1. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数 -> 1. 如果报错就返回 -> 1. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置 -> 1. 如果报错就返回 -> 1. `k`增加 1 +> 1. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串 +> 1. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性 +> 1. 如果报错就返回 +> 1. 如果`kPresent`等于`true`,则进行下面步骤 +> 1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性 +> 1. 如果报错就返回 +> 1. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数 +> 1. 如果报错就返回 +> 1. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置 +> 1. 如果报错就返回 +> 1. `k`增加 1 > 1. 返回`A` -仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 ii 时,`kPresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 +仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步中第 2 步时,`kPresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 ```javascript const arr = [, , ,]; From 165d5e0c19774c50c7778d5374d2a722da1a228c Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 3 May 2018 16:02:42 +0800 Subject: [PATCH 040/492] docs(class): edit class private property --- docs/class.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/class.md b/docs/class.md index f3171c5a6..5f0aa2872 100644 --- a/docs/class.md +++ b/docs/class.md @@ -460,7 +460,7 @@ class Point { } ``` -上面代码中,`#x`就表示私有属性`x`,在`Point`类之外是读取不到这个属性的。还可以看到,私有属性与实例的属性是可以同名的(比如,`#x`与`get x()`)。 +上面代码中,`#x`就是私有属性,在`Point`类之外是读取不到这个属性的。由于井号`#`是属性名的一部分,使用时必须带有`#`一起使用,所以`#x`和`x`是两个不同的属性。 私有属性可以指定初始值,在构造函数执行时进行初始化。 @@ -475,7 +475,7 @@ class Point { 之所以要引入一个新的前缀`#`表示私有属性,而没有采用`private`关键字,是因为 JavaScript 是一门动态语言,使用独立的符号似乎是唯一的可靠方法,能够准确地区分一种属性是否为私有属性。另外,Ruby 语言使用`@`表示私有属性,ES6 没有用这个符号而使用`#`,是因为`@`已经被留给了 Decorator。 -该提案只规定了私有属性的写法。但是,很自然地,它也可以用来写私有方法。 +这种写法不仅可以写私有属性,还可以用来写私有方法。 ```javascript class Foo { From 4533f407a79a65a85df41bc79a3e2b32587da69f Mon Sep 17 00:00:00 2001 From: wuzhiyu5 Date: Sat, 28 Apr 2018 13:57:38 +0800 Subject: [PATCH 041/492] =?UTF-8?q?=E4=BF=AE=E5=A4=8Des6=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E7=AB=A0=E8=8A=82=E9=93=BE=E6=8E=A5=E5=92=8C=E4=BC=AA=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/spec.md | 70 ++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 0374a769c..3d0cea915 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -111,7 +111,7 @@ ES6 规格将这个标准流程,使用简写的方式表达。 0 == null ``` -如果你不确定答案,或者想知道语言内部怎么处理,就可以去查看规格,[7.2.12 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-7.2.12)是对相等运算符(`==`)的描述。 +如果你不确定答案,或者想知道语言内部怎么处理,就可以去查看规格,[7.2.12 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-abstract-equality-comparison)是对相等运算符(`==`)的描述。 规格对每一种语法行为的描述,都分成两部分:先是总体的行为描述,然后是实现的算法细节。相等运算符的总体描述,只有一句话。 @@ -123,19 +123,19 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > 1. ReturnIfAbrupt(x). > 1. ReturnIfAbrupt(y). -> 1. If `Type(x)` is the same as `Type(y)`, then\ -> Return the result of performing Strict Equality Comparison `x === y`. +> 1. If `Type(x)` is the same as `Type(y)`, then +> 1. Return the result of performing Strict Equality Comparison `x === y`. > 1. If `x` is `null` and `y` is `undefined`, return `true`. > 1. If `x` is `undefined` and `y` is `null`, return `true`. -> 1. If `Type(x)` is Number and `Type(y)` is String, +> 1. If `Type(x)` is Number and `Type(y)` is String,
> return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is String and `Type(y)` is Number, +> 1. If `Type(x)` is String and `Type(y)` is Number,
> return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(x)` is Boolean, return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(y)` is Boolean, return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then +> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then
> return the result of the comparison `x == ToPrimitive(y)`. -> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then +> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then
> return the result of the comparison `ToPrimitive(x) == y`. > 1. Return `false`. @@ -154,7 +154,7 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > 1. 如果`Type(x)`是对象,`Type(y)`是字符串或数值或`Symbol`值,返回`ToPrimitive(x) == y`的结果。 > 1. 返回`false`。 -由于`0`的类型是数值,`null`的类型是 Null(这是规格[4.3.13 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-4.3.13)的规定,是内部 Type 运算的结果,跟`typeof`运算符无关)。因此上面的前 11 步都得不到结果,要到第 12 步才能得到`false`。 +由于`0`的类型是数值,`null`的类型是 Null(这是规格[4.3.13 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-null-type)的规定,是内部 Type 运算的结果,跟`typeof`运算符无关)。因此上面的前 11 步都得不到结果,要到第 12 步才能得到`false`。 ```javascript 0 == null // false @@ -199,7 +199,7 @@ a2.map(n => 1) // [, , ,] 为什么`a1`与`a2`成员的行为不一致?数组的成员是`undefined`或空位,到底有什么不同? -规格的[12.2.5 小节《数组的初始化》](http://www.ecma-international.org/ecma-262/6.0/#sec-12.2.5)给出了答案。 +规格的[12.2.5 小节《数组的初始化》](http://www.ecma-international.org/ecma-262/6.0/#sec-array-initializer)给出了答案。 > “Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array.” @@ -215,7 +215,7 @@ a2.map(n => 1) // [, , ,] ## 数组的 map 方法 -规格的[22.1.3.15 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-22.1.3.15)定义了数组的`map`方法。该小节先是总体描述`map`方法的行为,里面没有提到数组空位。 +规格的[22.1.3.15 小节](http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.map)定义了数组的`map`方法。该小节先是总体描述`map`方法的行为,里面没有提到数组空位。 后面的算法描述是这样的。 @@ -228,18 +228,18 @@ a2.map(n => 1) // [, , ,] > 1. Let `A` be `ArraySpeciesCreate(O, len)`. > 1. `ReturnIfAbrupt(A)`. > 1. Let `k` be 0. -> 1. Repeat, while `k` < `len`\ -> a. Let `Pk` be `ToString(k)`.\ -> b. Let `kPresent` be `HasProperty(O, Pk)`.\ -> c. `ReturnIfAbrupt(kPresent)`.\ -> d. If `kPresent` is `true`, then\ -> d-1. Let `kValue` be `Get(O, Pk)`.\ -> d-2. `ReturnIfAbrupt(kValue)`.\ -> d-3. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`.\ -> d-4. `ReturnIfAbrupt(mappedValue)`.\ -> d-5. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`.\ -> d-6. `ReturnIfAbrupt(status)`.\ -> e. Increase `k` by 1. +> 1. Repeat, while `k` < `len` +> 1. Let `Pk` be `ToString(k)`. +> 1. Let `kPresent` be `HasProperty(O, Pk)`. +> 1. `ReturnIfAbrupt(kPresent)`. +> 1. If `kPresent` is `true`, then +> 1. Let `kValue` be `Get(O, Pk)`. +> 1. `ReturnIfAbrupt(kValue)`. +> 1. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`. +> 1. `ReturnIfAbrupt(mappedValue)`. +> 1. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`. +> 1. `ReturnIfAbrupt(status)`. +> 1. Increase `k` by 1. > 1. Return `A`. 翻译如下。 @@ -253,21 +253,21 @@ a2.map(n => 1) // [, , ,] > 1. 生成一个新的数组`A`,跟当前数组的`length`属性保持一致 > 1. 如果报错就返回 > 1. 设定`k`等于 0 -> 1. 只要`k`小于当前数组的`length`属性,就重复下面步骤\ -> a. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串\ -> b. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性\ -> c. 如果报错就返回\ -> d. 如果`kPresent`等于`true`,则进行下面步骤\ -> d-1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性\ -> d-2. 如果报错就返回\ -> d-3. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数\ -> d-4. 如果报错就返回\ -> d-5. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置\ -> d-6. 如果报错就返回\ -> e. `k`增加 1 +> 1. 只要`k`小于当前数组的`length`属性,就重复下面步骤 +> 1. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串 +> 1. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性 +> 1. 如果报错就返回 +> 1. 如果`kPresent`等于`true`,则进行下面步骤 +> 1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性 +> 1. 如果报错就返回 +> 1. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数 +> 1. 如果报错就返回 +> 1. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置 +> 1. 如果报错就返回 +> 1. `k`增加 1 > 1. 返回`A` -仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 b 时,`kpresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 +仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 ii 时,`kPresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 ```javascript const arr = [, , ,]; From 31bef7b0bcc958560d8072508aac4a95ba0c37e5 Mon Sep 17 00:00:00 2001 From: wuzhiyu5 Date: Sat, 28 Apr 2018 15:14:33 +0800 Subject: [PATCH 042/492] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E4=BB=A5=E7=AC=A6=E5=90=88=E4=BC=AA=E4=BB=A3=E7=A0=81=E4=B8=AD?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/spec.md | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 3d0cea915..a7005870d 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -124,18 +124,18 @@ ES6 规格将这个标准流程,使用简写的方式表达。 > 1. ReturnIfAbrupt(x). > 1. ReturnIfAbrupt(y). > 1. If `Type(x)` is the same as `Type(y)`, then -> 1. Return the result of performing Strict Equality Comparison `x === y`. +> 1. Return the result of performing Strict Equality Comparison `x === y`. > 1. If `x` is `null` and `y` is `undefined`, return `true`. > 1. If `x` is `undefined` and `y` is `null`, return `true`. -> 1. If `Type(x)` is Number and `Type(y)` is String,
+> 1. If `Type(x)` is Number and `Type(y)` is String, > return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is String and `Type(y)` is Number,
+> 1. If `Type(x)` is String and `Type(y)` is Number, > return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(x)` is Boolean, return the result of the comparison `ToNumber(x) == y`. > 1. If `Type(y)` is Boolean, return the result of the comparison `x == ToNumber(y)`. -> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then
+> 1. If `Type(x)` is either String, Number, or Symbol and `Type(y)` is Object, then > return the result of the comparison `x == ToPrimitive(y)`. -> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then
+> 1. If `Type(x)` is Object and `Type(y)` is either String, Number, or Symbol, then > return the result of the comparison `ToPrimitive(x) == y`. > 1. Return `false`. @@ -229,17 +229,17 @@ a2.map(n => 1) // [, , ,] > 1. `ReturnIfAbrupt(A)`. > 1. Let `k` be 0. > 1. Repeat, while `k` < `len` -> 1. Let `Pk` be `ToString(k)`. -> 1. Let `kPresent` be `HasProperty(O, Pk)`. -> 1. `ReturnIfAbrupt(kPresent)`. -> 1. If `kPresent` is `true`, then -> 1. Let `kValue` be `Get(O, Pk)`. -> 1. `ReturnIfAbrupt(kValue)`. -> 1. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`. -> 1. `ReturnIfAbrupt(mappedValue)`. -> 1. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`. -> 1. `ReturnIfAbrupt(status)`. -> 1. Increase `k` by 1. +> 1. Let `Pk` be `ToString(k)`. +> 1. Let `kPresent` be `HasProperty(O, Pk)`. +> 1. `ReturnIfAbrupt(kPresent)`. +> 1. If `kPresent` is `true`, then +> 1. Let `kValue` be `Get(O, Pk)`. +> 1. `ReturnIfAbrupt(kValue)`. +> 1. Let `mappedValue` be `Call(callbackfn, T, «kValue, k, O»)`. +> 1. `ReturnIfAbrupt(mappedValue)`. +> 1. Let `status` be `CreateDataPropertyOrThrow (A, Pk, mappedValue)`. +> 1. `ReturnIfAbrupt(status)`. +> 1. Increase `k` by 1. > 1. Return `A`. 翻译如下。 @@ -254,20 +254,20 @@ a2.map(n => 1) // [, , ,] > 1. 如果报错就返回 > 1. 设定`k`等于 0 > 1. 只要`k`小于当前数组的`length`属性,就重复下面步骤 -> 1. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串 -> 1. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性 -> 1. 如果报错就返回 -> 1. 如果`kPresent`等于`true`,则进行下面步骤 -> 1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性 -> 1. 如果报错就返回 -> 1. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数 -> 1. 如果报错就返回 -> 1. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置 -> 1. 如果报错就返回 -> 1. `k`增加 1 +> 1. 设定`Pk`等于`ToString(k)`,即将`K`转为字符串 +> 1. 设定`kPresent`等于`HasProperty(O, Pk)`,即求当前数组有没有指定属性 +> 1. 如果报错就返回 +> 1. 如果`kPresent`等于`true`,则进行下面步骤 +> 1. 设定`kValue`等于`Get(O, Pk)`,取出当前数组的指定属性 +> 1. 如果报错就返回 +> 1. 设定`mappedValue`等于`Call(callbackfn, T, «kValue, k, O»)`,即执行回调函数 +> 1. 如果报错就返回 +> 1. 设定`status`等于`CreateDataPropertyOrThrow (A, Pk, mappedValue)`,即将回调函数的值放入`A`数组的指定位置 +> 1. 如果报错就返回 +> 1. `k`增加 1 > 1. 返回`A` -仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步的 ii 时,`kPresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 +仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步中第 2 步时,`kPresent`会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。 ```javascript const arr = [, , ,]; From 25cc21754d68e97f9b0d44bad70c31934448e47b Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 3 May 2018 16:57:30 +0800 Subject: [PATCH 043/492] docs(class-extends): fix super() #657 --- docs/class-extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index c96d8f77e..e19c5631b 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -29,7 +29,7 @@ class ColorPoint extends Point { 上面代码中,`constructor`方法和`toString`方法之中,都出现了`super`关键字,它在这里表示父类的构造函数,用来新建父类的`this`对象。 -子类必须在`constructor`方法中调用`super`方法,否则新建实例时会报错。这是因为子类没有自己的`this`对象,而是继承父类的`this`对象,然后对其进行加工。如果不调用`super`方法,子类就得不到`this`对象。 +子类必须在`constructor`方法中调用`super`方法,否则新建实例时会报错。这是因为子类自己的`this`对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用`super`方法,子类就得不到`this`对象。 ```javascript class Point { /* ... */ } From 6733d07c719765cb909edb5ef618cda648bf99b1 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 3 May 2018 17:21:01 +0800 Subject: [PATCH 044/492] docs(proposal): edit BigInt --- docs/proposals.md | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/proposals.md b/docs/proposals.md index 06af7ae34..a502f9796 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -535,6 +535,13 @@ Math.pow(2, 1024) // Infinity 现在有一个[提案](https://github.com/tc39/proposal-bigint),引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。 +```javascript +const a = 2172141653n; +const b = 15346349309n; +a * b // 33334444555566667777n +Number(a) * Number(b) // 33334444555566670000 +``` + 为了与 Number 类型区别,BigInt 类型的数据必须使用后缀`n`表示。 ```javascript @@ -553,7 +560,7 @@ BigInt 同样可以使用各种进制表示,都要加上后缀`n`。 `typeof`运算符对于 BigInt 类型的数据返回`bigint`。 ```javascript -typeof 123n // 'BigInt' +typeof 123n // 'bigint' ``` ### BigInt 对象 @@ -625,29 +632,41 @@ Integer 类型不能与 Number 类型进行混合运算。 上面代码报错是因为无论返回的是 BigInt 或 Number,都会导致丢失信息。比如`(2n**53n + 1n) + 0.5`这个表达式,如果返回 BigInt 类型,`0.5`这个小数部分会丢失;如果返回 Number 类型,有效精度只能保持 53 位,导致精度下降。 +同样的原因,如果一个标准库函数的参数预期是 Number 类型,但是得到的是一个 BigInt,就会报错。 + +```javascript +// 错误的写法 +Math.sqrt(4n) // 报错 + +// 正确的写法 +Math.sqrt(Number(4n)) // 2 +``` + +上面代码中,`Math.sqrt`的参数预期是 Number 类型,如果是 BigInt 就会报错,必须先用`Number`方法转一下类型,才能进行计算。 + asm.js 里面,`|0`跟在一个数值的后面会返回一个32位整数。根据不能与 Number 类型混合运算的规则,BigInt 如果与`|0`进行运算会报错。 ```javascript 1n | 0 // 报错 ``` -相等运算符(`==`)会改变数据类型,也是不允许混合使用。 +比较运算符(比如`>`)和相等运算符(`==`)允许 BigInt 与其他类型的值混合计算,因为这样做不会损失精度。 ```javascript -0n == 0 -// 报错 TypeError - -0n == false -// 报错 TypeError +0n < 1 // true +0n < true // true +0n == 0 // true +0n == false // true ``` -精确相等运算符(`===`)不会改变数据类型,因此可以混合使用。 +同理,精确相等运算符(`===`)也可以混合使用。 ```javascript -0n === 0 -// false +0n === 0 // false ``` +上面代码中,由于`0n`与`0`的数据类型不同,所以返回`false`。 + 大整数可以转为其他数据类型。 ```javascript From 58767f55b2e339cb1d095b21083f42e1c965cc7b Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 9 May 2018 11:26:52 +0800 Subject: [PATCH 045/492] docs(async): edit async --- docs/async.md | 2 +- docs/module.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/async.md b/docs/async.md index 0a12272d2..b411cb6c5 100644 --- a/docs/async.md +++ b/docs/async.md @@ -913,7 +913,7 @@ async function* prefixLines(asyncIterable) { } ``` -异步 Generator 函数的返回值是一个异步 Iterator,即每次调用它的`next`方法,会返回一个 Promise 对象,也就是说,跟在`yield`命令后面的,应该是一个 Promise 对象。 +异步 Generator 函数的返回值是一个异步 Iterator,即每次调用它的`next`方法,会返回一个 Promise 对象,也就是说,跟在`yield`命令后面的,应该是一个 Promise 对象。如果像上面那个例子那样,`yield`命令后面是一个字符串,会被自动包装成一个 Promise 对象。 ```javascript function fetchRandom() { diff --git a/docs/module.md b/docs/module.md index 4fc5085ef..f9ddc8ed4 100644 --- a/docs/module.md +++ b/docs/module.md @@ -650,7 +650,7 @@ import {db, users} from './index'; ### 简介 -前面介绍过,`import`命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(`import`命令叫做”连接“ binding 其实更合适)。所以,下面的代码会报错。 +前面介绍过,`import`命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(`import`命令叫做“连接” binding 其实更合适)。所以,下面的代码会报错。 ```javascript // 报错 From df00e8abba44601954f61dca0d0cf964587d4e22 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 9 May 2018 13:06:28 +0800 Subject: [PATCH 046/492] docs(set): edit WeakMap --- docs/set-map.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/set-map.md b/docs/set-map.md index 9d930845b..d223fca4b 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -988,7 +988,7 @@ wm.get(key) ### WeakMap 的语法 -WeakMap 与 Map 在 API 上的区别主要是两个,一是没有遍历操作(即没有`key()`、`values()`和`entries()`方法),也没有`size`属性。因为没有办法列出所有键名,某个键名是否存在完全不可预测,跟垃圾回收机制是否运行相关。这一刻可以取到键名,下一刻垃圾回收机制突然运行了,这个键名就没了,为了防止出现不确定性,就统一规定不能取到键名。二是无法清空,即不支持`clear`方法。因此,`WeakMap`只有四个方法可用:`get()`、`set()`、`has()`、`delete()`。 +WeakMap 与 Map 在 API 上的区别主要是两个,一是没有遍历操作(即没有`keys()`、`values()`和`entries()`方法),也没有`size`属性。因为没有办法列出所有键名,某个键名是否存在完全不可预测,跟垃圾回收机制是否运行相关。这一刻可以取到键名,下一刻垃圾回收机制突然运行了,这个键名就没了,为了防止出现不确定性,就统一规定不能取到键名。二是无法清空,即不支持`clear`方法。因此,`WeakMap`只有四个方法可用:`get()`、`set()`、`has()`、`delete()`。 ```javascript const wm = new WeakMap(); From 7d5a56292aefec91b000a691143de6fdd2dfbe27 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 16 May 2018 14:16:28 +0800 Subject: [PATCH 047/492] docs(proxy): edit receiver --- docs/proxy.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/proxy.md b/docs/proxy.md index 2f602b848..c7dfa8c04 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -277,7 +277,7 @@ const el = dom.div({}, document.body.appendChild(el); ``` -下面是一个`get`方法的第三个参数的例子。 +下面是一个`get`方法的第三个参数的例子,它总是指向原始的读操作所在的那个对象,一般情况下就是 Proxy 实例。 ```javascript const proxy = new Proxy({}, { @@ -288,7 +288,20 @@ const proxy = new Proxy({}, { proxy.getReceiver === proxy // true ``` -上面代码中,`get`方法的第三个参数`receiver`,总是为当前的 Proxy 实例。 +上面代码中,`proxy`对象的`getReceiver`属性是由`proxy`对象提供的,所以`receiver`指向`proxy`对象。 + +```javascript +const proxy = new Proxy({}, { + get: function(target, property, receiver) { + return receiver; + } +}); + +const d = Object.create(proxy); +d.a === d // true +``` + +上面代码中,`d`对象本身没有`a`属性,所以读取`d.a`的时候,会去`d`的原型`proxy`对象找。这时,`receiver`就指向`d`,代表原始的读操作所在的那个对象。 如果一个属性不可配置(configurable)和不可写(writable),则该属性不能被代理,通过 Proxy 对象访问该属性会报错。 @@ -389,7 +402,7 @@ proxy.foo = 'bar'; proxy.foo === proxy // true ``` -上面代码中,`set`方法的第四个参数`receiver`,指的是操作行为所在的那个对象,一般情况下是`proxy`实例本身,请看下面的例子。 +上面代码中,`set`方法的第四个参数`receiver`,指的是原始的操作行为所在的那个对象,一般情况下是`proxy`实例本身,请看下面的例子。 ```javascript const handler = { From 9708a2158135c5fa82a0930ed0a2d465463de9c5 Mon Sep 17 00:00:00 2001 From: Simon Ma Date: Wed, 16 May 2018 20:43:29 +0800 Subject: [PATCH 048/492] Update proxy.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 纠正错别字 > **构建函数** 为 构造函数 2. 纠正语义 > 有被`for...in`循环所排除。 3. 增加 > `has` 方法的参数说明 --- docs/proxy.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/proxy.md b/docs/proxy.md index c7dfa8c04..e486078da 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -503,6 +503,8 @@ Reflect.apply(proxy, null, [9, 10]) // 38 `has`方法用来拦截`HasProperty`操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是`in`运算符。 +`has`方法可以接受两个参数,分别是目标对象、需查询的属性名。 + 下面的例子使用`has`方法隐藏某些属性,不被`in`运算符发现。 ```javascript @@ -579,7 +581,7 @@ for (let b in oproxy2) { // 99 ``` -上面代码中,`has`拦截只对`in`运算符生效,对`for...in`循环不生效,导致不符合要求的属性没有被排除在`for...in`循环之外。 +上面代码中,`has`拦截只对`in`运算符生效,对`for...in`循环不生效,导致不符合要求的属性没有被`for...in`循环所排除。 ### construct() @@ -596,7 +598,7 @@ var handler = { `construct`方法可以接受两个参数。 - `target`: 目标对象 -- `args`:构建函数的参数对象 +- `args`:构造函数的参数对象 下面是一个例子。 From 2d86fc3f9c1302bf1c6926bb8ff41e2d25b8e5c1 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 17 May 2018 22:39:21 +0800 Subject: [PATCH 049/492] docs(generator): edit throw --- docs/generator.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/generator.md b/docs/generator.md index fde9a9816..89127cfbd 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -534,6 +534,24 @@ g.throw(); 上面代码中,`g.throw`抛出错误以后,没有任何`try...catch`代码块可以捕获这个错误,导致程序报错,中断执行。 +`throw`方法抛出的错误要被内部捕获,前提是必须至少执行过一次`next`方法。 + +```javascript +function* gen() { + try { + yield 1; + } catch (e) { + console.log('内部捕获'); + } +} + +var g = gen(); +g.throw(1); +// Uncaught 1 +``` + +上面代码中,`g.throw(1)`执行时,`next`方法一次都没有执行过。这时,抛出的错误不会被内部捕获,而是直接在外部抛出,导致程序出错。这种行为其实很好理解,因为第一次执行`next`方法,等同于启动执行 Generator 函数的内部代码,否则 Generator 函数还没有开始执行,这时`throw`方法抛错只可能抛出在函数外部。 + `throw`方法被捕获以后,会附带执行下一条`yield`表达式。也就是说,会附带执行一次`next`方法。 ```javascript From 7c7f1ce7d1cec390f6fad2a605b962b08b07dd19 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sun, 20 May 2018 06:37:23 +0800 Subject: [PATCH 050/492] docs(proxy): edit proxyw --- docs/generator.md | 2 +- docs/proxy.md | 12 +++++------- docs/regex.md | 20 +++++++++++++++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/generator.md b/docs/generator.md index 89127cfbd..4e5a0a128 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -1233,7 +1233,7 @@ var clock = function* () { Generator 函数是 ES6 对协程的实现,但属于不完全实现。Generator 函数被称为“半协程”(semi-coroutine),意思是只有 Generator 函数的调用者,才能将程序的执行权还给 Generator 函数。如果是完全执行的协程,任何函数都可以让暂停的协程继续执行。 -如果将 Generator 函数当作协程,完全可以将多个需要互相协作的任务写成 Generator 函数,它们之间使用`yield`表示式交换控制权。 +如果将 Generator 函数当作协程,完全可以将多个需要互相协作的任务写成 Generator 函数,它们之间使用`yield`表达式交换控制权。 ### Generator 与上下文 diff --git a/docs/proxy.md b/docs/proxy.md index c7dfa8c04..51f02d40a 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -595,10 +595,9 @@ var handler = { `construct`方法可以接受两个参数。 -- `target`: 目标对象 -- `args`:构建函数的参数对象 - -下面是一个例子。 +- `target`:目标对象 +- `args`:构造函数的参数对象 +- `newTarget`:创造实例对象时,`new`命令作用的构造函数(下面例子的`p`) ```javascript var p = new Proxy(function () {}, { @@ -664,11 +663,10 @@ var handler = { }; var target = {}; var proxy = new Proxy(target, handler); -proxy.foo = 'bar' -// TypeError: proxy defineProperty handler returned false for property '"foo"' +proxy.foo = 'bar' // 不会生效 ``` -上面代码中,`defineProperty`方法返回`false`,导致添加新属性会抛出错误。 +上面代码中,`defineProperty`方法返回`false`,导致添加新属性总是无效。 注意,如果目标对象不可扩展(extensible),则`defineProperty`不能增加目标对象上不存在的属性,否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),则`defineProperty`方法不得改变这两个设置。 diff --git a/docs/regex.md b/docs/regex.md index 4ee07ed01..71390bfba 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -132,6 +132,20 @@ codePointLength(s) // 2 上面代码中,不加`u`修饰符,就无法识别非规范的`K`字符。 +## RegExp.prototype.unicode 属性 + +正则实例对象新增`unicode`属性,表示是否设置了`u`修饰符。 + +```javascript +const r1 = /hello/; +const r2 = /hello/u; + +r1.unicode // false +r2.unicode // true +``` + +上面代码中,正则表达式是否设置了`u`修饰符,可以从`unicode`属性看出来。 + ## y 修饰符 除了`u`修饰符,ES6 还为正则表达式添加了`y`修饰符,叫做“粘连”(sticky)修饰符。 @@ -264,16 +278,16 @@ tokenize(TOKEN_G, '3x + 4') 上面代码中,`g`修饰符会忽略非法字符,而`y`修饰符不会,这样就很容易发现错误。 -## sticky 属性 +## RegExp.prototype.sticky 属性 -与`y`修饰符相匹配,ES6 的正则对象多了`sticky`属性,表示是否设置了`y`修饰符。 +与`y`修饰符相匹配,ES6 的正则实例对象多了`sticky`属性,表示是否设置了`y`修饰符。 ```javascript var r = /hello\d/y; r.sticky // true ``` -## flags 属性 +## RegExp.prototype.flags 属性 ES6 为正则表达式新增了`flags`属性,会返回正则表达式的修饰符。 From 1ac13240a9ca81ebb5d615a1df77a87ccc9db628 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Mon, 21 May 2018 14:31:10 +0800 Subject: [PATCH 051/492] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BE=AA=E7=8E=AF=E5=BA=94=E7=94=A8=E7=AB=A0=E8=8A=82?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8F=98=E9=87=8F=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit odd 中的 even 应为 undefined 而不是 null --- docs/module-loader.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/module-loader.md b/docs/module-loader.md index a5ee61500..106410fdf 100644 --- a/docs/module-loader.md +++ b/docs/module-loader.md @@ -729,7 +729,7 @@ module.exports = function (n) { } ``` -上面代码中,`even.js`加载`odd.js`,而`odd.js`又去加载`even.js`,形成“循环加载”。这时,执行引擎就会输出`even.js`已经执行的部分(不存在任何结果),所以在`odd.js`之中,变量`even`等于`null`,等到后面调用`even(n - 1)`就会报错。 +上面代码中,`even.js`加载`odd.js`,而`odd.js`又去加载`even.js`,形成“循环加载”。这时,执行引擎就会输出`even.js`已经执行的部分(不存在任何结果),所以在`odd.js`之中,变量`even`等于`undefined`,等到后面调用`even(n - 1)`就会报错。 ```bash $ node From 76b6bce980e830a84038ce0caf54aeafa796697e Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 22 May 2018 12:34:53 +0800 Subject: [PATCH 052/492] docs(generator): edit generator --- docs/class-extends.md | 2 +- docs/generator.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index e19c5631b..a81df72a9 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -499,7 +499,7 @@ A.__proto__ === Function.prototype // true A.prototype.__proto__ === undefined // true ``` -这种情况与第二种情况非常像。`A`也是一个普通函数,所以直接继承`Function.prototype`。但是,`A`调用后返回的对象不继承任何方法,所以它的`__proto__`指向`Function.prototype`,即实质上执行了下面的代码。 +这种情况与第二种情况非常像。`A`也是一个普通函数,所以直接继承`Function.prototype`。但是,`A`调用后返回的对象不继承任何方法,所以它的`__proto__`指向`undefined`,即实质上执行了下面的代码。 ```javascript class C extends null { diff --git a/docs/generator.md b/docs/generator.md index 4e5a0a128..e679bf2a7 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -336,8 +336,8 @@ for (let v of foo()) { function* fibonacci() { let [prev, curr] = [0, 1]; for (;;) { - [prev, curr] = [curr, prev + curr]; yield curr; + [prev, curr] = [curr, prev + curr]; } } From 4f5db47055d1a7380fa38394d0eaf6b222ec7988 Mon Sep 17 00:00:00 2001 From: taxilng <769967440@qq.com> Date: Tue, 22 May 2018 14:30:21 +0800 Subject: [PATCH 053/492] Update object.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __proto__属性:第一个例子,注释,ES5,ES6写反了 --- docs/object.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/object.md b/docs/object.md index b93b53513..1ca5a90cf 100644 --- a/docs/object.md +++ b/docs/object.md @@ -861,13 +861,13 @@ JavaScript 语言的对象继承是通过原型链实现的。ES6 提供了更 `__proto__`属性(前后各两个下划线),用来读取或设置当前对象的`prototype`对象。目前,所有浏览器(包括 IE11)都部署了这个属性。 ```javascript -// es6 的写法 +// es5 的写法 const obj = { method: function() { ... } }; obj.__proto__ = someOtherObj; -// es5 的写法 +// es6 的写法 var obj = Object.create(someOtherObj); obj.method = function() { ... }; ``` From 54eba0dc17a4b31f0b87c5f4bf7e5834bc68e5ec Mon Sep 17 00:00:00 2001 From: taxilng <769967440@qq.com> Date: Thu, 24 May 2018 10:30:28 +0800 Subject: [PATCH 054/492] Update symbol.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit demo不能在游览器上直接运行,故修改下; --- docs/symbol.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/symbol.md b/docs/symbol.md index 90126a310..f86005be1 100644 --- a/docs/symbol.md +++ b/docs/symbol.md @@ -163,13 +163,15 @@ let obj = { Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的。 ```javascript +const log = {}; + log.levels = { DEBUG: Symbol('debug'), INFO: Symbol('info'), WARN: Symbol('warn') }; -log(log.levels.DEBUG, 'debug message'); -log(log.levels.INFO, 'info message'); +console.log(log.levels.DEBUG, 'debug message'); +console.log(log.levels.INFO, 'info message'); ``` 下面是另外一个例子。 From dfd5c0ac0e0039dabf91999393675adbdce385c4 Mon Sep 17 00:00:00 2001 From: shenzhim Date: Thu, 31 May 2018 19:30:36 +0800 Subject: [PATCH 055/492] =?UTF-8?q?@std/esm=20=E5=B7=B2=E7=BB=8Fdeprecated?= =?UTF-8?q?=EF=BC=8C=E6=94=B9=E4=B8=BAesm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/async.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/async.md b/docs/async.md index b411cb6c5..02c174e3d 100644 --- a/docs/async.md +++ b/docs/async.md @@ -460,7 +460,7 @@ async function dbFuc(db) { } ``` -目前,[`@std/esm`](https://www.npmjs.com/package/@std/esm)模块加载器支持顶层`await`,即`await`命令可以不放在 async 函数里面,直接使用。 +目前,[`esm`](https://www.npmjs.com/package/esm)模块加载器支持顶层`await`,即`await`命令可以不放在 async 函数里面,直接使用。 ```javascript // async 函数的写法 @@ -476,7 +476,7 @@ const res = await fetch('google.com'); console.log(await res.text()); ``` -上面代码中,第二种写法的脚本必须使用`@std/esm`加载器,才会生效。 +上面代码中,第二种写法的脚本必须使用`esm`加载器,才会生效。 ## async 函数的实现原理 From 42e06a84d9ef75f7547ff4584802494c55d3c82a Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 4 Jun 2018 11:12:30 +0800 Subject: [PATCH 056/492] docs(reference): edit reference --- docs/proxy.md | 4 ++-- docs/reference.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/proxy.md b/docs/proxy.md index d7bfbfe3e..6120bbae3 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -303,7 +303,7 @@ d.a === d // true 上面代码中,`d`对象本身没有`a`属性,所以读取`d.a`的时候,会去`d`的原型`proxy`对象找。这时,`receiver`就指向`d`,代表原始的读操作所在的那个对象。 -如果一个属性不可配置(configurable)和不可写(writable),则该属性不能被代理,通过 Proxy 对象访问该属性会报错。 +如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错。 ```javascript const target = Object.defineProperties({}, { @@ -420,7 +420,7 @@ myObj.foo === myObj // true 上面代码中,设置`myObj.foo`属性的值时,`myObj`并没有`foo`属性,因此引擎会到`myObj`的原型链去找`foo`属性。`myObj`的原型对象`proxy`是一个 Proxy 实例,设置它的`foo`属性会触发`set`方法。这时,第四个参数`receiver`就指向原始赋值行为所在的对象`myObj`。 -注意,如果目标对象自身的某个属性,不可写或不可配置,那么`set`方法将不起作用。 +注意,如果目标对象自身的某个属性,不可写且不可配置,那么`set`方法将不起作用。 ```javascript const obj = {}; diff --git a/docs/reference.md b/docs/reference.md index 795c61ee2..9d2330fe1 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -140,6 +140,7 @@ ## Promise 对象 - Jake Archibald, [JavaScript Promises: There and back again](http://www.html5rocks.com/en/tutorials/es6/promises/) +- Jake Archibald, [Tasks, microtasks, queues and schedules](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) - Tilde, [rsvp.js](https://github.com/tildeio/rsvp.js) - Sandeep Panda, [An Overview of JavaScript Promises](http://www.sitepoint.com/overview-javascript-promises/): ES6 Promise 入门介绍 - Dave Atchley, [ES6 Promises](http://www.datchley.name/es6-promises/): Promise 的语法介绍 From 688ca45e6fb0ad3e0d3c5904dde3ccf486fc7a37 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 5 Jun 2018 13:33:35 +0800 Subject: [PATCH 057/492] docs(Reflect): fix Reflect.setPrototypeOf #693 --- docs/reflect.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/reflect.md b/docs/reflect.md index ff3fd579b..7ee1dbcfd 100644 --- a/docs/reflect.md +++ b/docs/reflect.md @@ -313,16 +313,27 @@ Reflect.getPrototypeOf(1) // 报错 ### Reflect.setPrototypeOf(obj, newProto) -`Reflect.setPrototypeOf`方法用于设置对象的`__proto__`属性,返回第一个参数对象,对应`Object.setPrototypeOf(obj, newProto)`。 +`Reflect.setPrototypeOf`方法用于设置目标对象的原型(prototype),对应`Object.setPrototypeOf(obj, newProto)`方法。它返回一个布尔值,表示是否设置成功。 ```javascript -const myObj = new FancyThing(); +const myObj = {}; // 旧写法 -Object.setPrototypeOf(myObj, OtherThing.prototype); +Object.setPrototypeOf(myObj, Array.prototype); // 新写法 -Reflect.setPrototypeOf(myObj, OtherThing.prototype); +Reflect.setPrototypeOf(myObj, Array.prototype); + +myObj.length // 0 +``` + +如果无法设置目标对象的原型(比如,目标对象禁止扩展),`Reflect.setPrototypeOf`方法返回`false`。 + +```javascript +Reflect.setPrototypeOf({}, null) +// true +Reflect.setPrototypeOf(Object.freeze({}), null) +// false ``` 如果第一个参数不是对象,`Object.setPrototypeOf`会返回第一个参数本身,而`Reflect.setPrototypeOf`会报错。 From cdc7e48d939cab5a0027664b65bcd228ede46ee8 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 5 Jun 2018 16:48:43 +0800 Subject: [PATCH 058/492] docs(array): edit spread operator #694 --- docs/array.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/array.md b/docs/array.md index 30137c236..7f6fd379f 100644 --- a/docs/array.md +++ b/docs/array.md @@ -163,24 +163,34 @@ const [...a2] = a1; 扩展运算符提供了数组合并的新写法。 ```javascript -// ES5 -[1, 2].concat(more) -// ES6 -[1, 2, ...more] - -var arr1 = ['a', 'b']; -var arr2 = ['c']; -var arr3 = ['d', 'e']; +const arr1 = ['a', 'b']; +const arr2 = ['c']; +const arr3 = ['d', 'e']; -// ES5的合并数组 +// ES5 的合并数组 arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] -// ES6的合并数组 +// ES6 的合并数组 [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ] ``` +不过,这两种方法都是浅拷贝,使用的时候需要注意。 + +```javascript +const a1 = [{ foo: 1 }]; +const a2 = [{ bar: 2 }]; + +const a3 = a1.concat(a2); +const a4 = [...a1, ...a2]; + +a3[0] === a1[0] // true +a4[0] === a1[0] // true +``` + +上面代码中,`a3`和`a4`是用两种不同方法合并而成的新数组,但是它们的成员都是对原数组成员的引用,这就是浅拷贝。如果修改了原数组的成员,会同步反映到新数组。 + **(3)与解构赋值结合** 扩展运算符可以与解构赋值结合起来,用于生成数组。 From 6583714f3bb1ef5e921c3064bbccc97d2f04f2f8 Mon Sep 17 00:00:00 2001 From: snow212-cn Date: Thu, 7 Jun 2018 22:34:19 +0800 Subject: [PATCH 059/492] Update object.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这两段不知所云的英文插进代码段要干什么 --- docs/object.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/object.md b/docs/object.md index 1ca5a90cf..a1c2bdc2c 100644 --- a/docs/object.md +++ b/docs/object.md @@ -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`,这两个值会被忽略,不会报错。 From e4351e2a70cff6ff58337fd313b11875d3eba2cc Mon Sep 17 00:00:00 2001 From: favefan Date: Thu, 21 Jun 2018 09:28:48 +0800 Subject: [PATCH 060/492] word change. --- docs/let.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/let.md b/docs/let.md index 112022907..026b8aefb 100644 --- a/docs/let.md +++ b/docs/let.md @@ -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`这些方法都可能无法使用。 综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。 From 19e1974afe27c5b1ab192470618e1d2a989c3078 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 21 Jun 2018 16:40:25 +0800 Subject: [PATCH 061/492] docs: edit class-extends --- docs/class-extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index a81df72a9..3d39842f5 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -713,7 +713,7 @@ function mix(...mixins) { class Mix {} for (let mixin of mixins) { - copyProperties(Mix, mixin); // 拷贝实例属性 + copyProperties(Mix.prototype, new mixin()); // 拷贝实例属性 copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性 } From 83bad90346c8c2486d8fa844bd7a0463757428bf Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 21 Jun 2018 16:57:09 +0800 Subject: [PATCH 062/492] docs: edit class-extends --- docs/class-extends.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 3d39842f5..867868d0c 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -713,8 +713,8 @@ function mix(...mixins) { class Mix {} for (let mixin of mixins) { - copyProperties(Mix.prototype, new mixin()); // 拷贝实例属性 - copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性 + copyProperties(Mix.prototype, mixin); // 拷贝实例属性 + copyProperties(Mix.prototype, Object.getPrototypeOf(mixin)); // 拷贝原型属性 } return Mix; From 3c44084f4b2e318fcbec77b7191b1f2412726c47 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 25 Jun 2018 12:26:32 +0800 Subject: [PATCH 063/492] =?UTF-8?q?docs(class-extends):=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20class=20X=20extends=20null=20=E7=9A=84=E8=AE=A8?= =?UTF-8?q?=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/class-extends.md | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 867868d0c..098b81bdc 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -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__`属性。也就是说,子类的原型的原型,是父类的原型。 @@ -714,7 +692,7 @@ function mix(...mixins) { for (let mixin of mixins) { copyProperties(Mix.prototype, mixin); // 拷贝实例属性 - copyProperties(Mix.prototype, Object.getPrototypeOf(mixin)); // 拷贝原型属性 + copyProperties(Mix.prototype, Reflect.getPrototypeOf(mixin)); // 拷贝原型属性 } return Mix; From e85f4dd15a17713d076524f8f131f7f0ddb04450 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 2 Jul 2018 14:16:27 +0800 Subject: [PATCH 064/492] docs(iterator): edit return() #708 --- docs/iterator.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/iterator.md b/docs/iterator.md index a05753f63..a8091062f 100644 --- a/docs/iterator.md +++ b/docs/iterator.md @@ -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,12 +505,6 @@ 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(); From efafe678d1fe16c9a405a7b328941d33a460ac53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Shaoyao=C2=B7=E7=90=9A?= Date: Wed, 4 Jul 2018 08:11:26 +0200 Subject: [PATCH 065/492] Update module.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正描述 --- docs/module.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/module.md b/docs/module.md index f9ddc8ed4..f27c0f87f 100644 --- a/docs/module.md +++ b/docs/module.md @@ -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() From d4c8df426ab9942a745584998754fe0ae114e44d Mon Sep 17 00:00:00 2001 From: ruanyf Date: Fri, 6 Jul 2018 10:32:43 +0800 Subject: [PATCH 066/492] docs(class-extends): fix super() #711 --- docs/class-extends.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 098b81bdc..617dfaf05 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -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 { From a46664f54abb9742fe22cb31285b1cac8c7929a9 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Fri, 6 Jul 2018 10:36:01 +0800 Subject: [PATCH 067/492] docs(iterator): fix return() --- docs/iterator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/iterator.md b/docs/iterator.md index a8091062f..a39352c4a 100644 --- a/docs/iterator.md +++ b/docs/iterator.md @@ -511,7 +511,7 @@ for (let line of readLinesSync(fileName)) { } ``` -上面代码中,情况一输出文件的第一行以后,就会执行`return`方法,关闭这个文件;情况二输出所有行以后,执行`return`方法,关闭该文件;情况三会在执行`return`方法关闭文件之后,再抛出错误。 +上面代码中,情况一输出文件的第一行以后,就会执行`return`方法,关闭这个文件;情况二会在执行`return`方法关闭文件之后,再抛出错误。 注意,`return`方法必须返回一个对象,这是 Generator 规格决定的。 From 94024df0f113114bf7ad9e5293fa2d5c8da19f77 Mon Sep 17 00:00:00 2001 From: hanty <841609790@qq.com> Date: Wed, 11 Jul 2018 14:46:51 +0800 Subject: [PATCH 068/492] Update async.md --- docs/async.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/async.md b/docs/async.md index 02c174e3d..b3931fa28 100644 --- a/docs/async.md +++ b/docs/async.md @@ -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 From 0fe548fd2b7c8a6a073104a2c52faa75fff41f86 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 17 Jul 2018 12:25:16 +0800 Subject: [PATCH 069/492] docs(let): edit const #720 --- docs/let.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/let.md b/docs/let.md index 026b8aefb..a8b4ddec6 100644 --- a/docs/let.md +++ b/docs/let.md @@ -494,7 +494,7 @@ const age = 30; ### 本质 -`const`实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,`const`只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。 +`const`实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,`const`只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。 ```javascript const foo = {}; From 420a9f76f8651a511c73e0a09cba6cef80afba93 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 17 Jul 2018 21:42:52 +0800 Subject: [PATCH 070/492] docs(let): fix const #720 --- docs/let.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/let.md b/docs/let.md index 112022907..a2dae6fa6 100644 --- a/docs/let.md +++ b/docs/let.md @@ -494,7 +494,7 @@ const age = 30; ### 本质 -`const`实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,`const`只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。 +`const`实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,`const`只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。 ```javascript const foo = {}; From 3034d8e4ed0e29a6bcd3c1e5699536a351037c7f Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 24 Jul 2018 11:06:49 +0800 Subject: [PATCH 071/492] refact: cancel inline JS codes --- config.js | 1 + index.html | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/config.js b/config.js index 2ea5eb093..f0c3ad930 100644 --- a/config.js +++ b/config.js @@ -24,3 +24,4 @@ function addConfig(obj, conf) { }); } +ditto.run(); diff --git a/index.html b/index.html index 66a636001..98936328a 100644 --- a/index.html +++ b/index.html @@ -28,9 +28,6 @@
-