diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 3b34736d6b..c40a43443f 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -68,7 +68,7 @@ JavaScript 的能力很大程度上取决于它运行的环境。例如,[Node. 现代浏览器允许 JavaScript 做一些文件相关的操作,但是这个操作是受到限制的。仅当用户做出特定的行为,JavaScript 才能操作这个文件。例如,用户把文件“拖放”到浏览器中,或者通过 `` 标签选择了文件。 有很多与相机/麦克风和其它设备进行交互的方式,但是这些都需要获得用户的明确许可。因此,启用了 JavaScript 的网页应该不会偷偷地启动网络摄像头观察你,并把你的信息发送到 [美国国家安全局](https://en.wikipedia.org/wiki/National_Security_Agency)。 -- 不同的标签页/窗口之间通常互不了解。有时候,也会有一些联系。例如,一个标签页通过 JavaScript 打开另外一个标签页。但即使在这种情况下,如果两个标签页打开的不是同一个网站(域名、协议或者端口任一不相同的网站),它们都不能相互通信。 +- 不同的标签页/窗口之间通常互不了解。有时候,也会有一些联系,例如一个标签页通过 JavaScript 打开的另外一个标签页。但即使在这种情况下,如果两个标签页打开的不是同一个网站(域名、协议或者端口任一不相同的网站),它们都不能相互通信。 这就是所谓的“同源策略”。为了解决“同源策略”问题,两个标签页必须 **都** 包含一些处理这个问题的特定的 JavaScript 代码,并均允许数据交换。本教程会讲到这部分相关的知识。 diff --git a/1-js/03-code-quality/02-coding-style/article.md b/1-js/03-code-quality/02-coding-style/article.md index dac9e674b9..f5c3ddee01 100644 --- a/1-js/03-code-quality/02-coding-style/article.md +++ b/1-js/03-code-quality/02-coding-style/article.md @@ -328,7 +328,7 @@ function pow(x, n) { }, "rules": { "no-console": 0, - "indent": ["warning", 2] + "indent": 2 } } ``` diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 1e416b2587..4822861c70 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -23,8 +23,8 @@ JavaScript 引擎背后的团队关于首先要实现什么有着他们自己想 2. 第二,polyfill。 - 新的语言特性可能包括新的内建函数和语法结构。 - transpiler 会重写代码,将语法结构转换为旧的结构。但是对于新的内建函数,需要我们去实现。JavaScript 是一个高度动态化的语言。脚本可以添加/修改任何函数,从而使它们的行为符合现代标准。 + 新的语言特性可能不仅包括语法结构,还包括新的内建函数。 + Transpiler 会重写代码,将语法结构转换为旧的结构。但是对于新的内建函数,需要我们去实现。JavaScript 是一个高度动态化的语言。脚本可以添加/修改任何函数,从而使它们的行为符合现代标准。 更新/添加新函数的脚本称为 “polyfill”。它“填补”了缺口,并添加了缺少的实现。 diff --git a/1-js/04-object-basics/03-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md index 2df08db780..d4cb6f74ae 100644 --- a/1-js/04-object-basics/03-garbage-collection/article.md +++ b/1-js/04-object-basics/03-garbage-collection/article.md @@ -23,7 +23,7 @@ JavaScript 中主要的内存管理概念是 **可达性**。 2. 如果一个值可以通过引用或引用链从根访问任何其他值,则认为该值是可达的。 - 比方说,如果全局变量中有一个对象,并且该对象有一个属性引用了另一个对象,则该对象被认为是可达的。而且它引用的内容也是可达的。下面是详细的例子。 + 比方说,如果全局变量中有一个对象,并且该对象有一个属性引用了另一个对象,则 **该** 对象被认为是可达的。而且它引用的内容也是可达的。下面是详细的例子。 在 JavaScript 引擎中有一个被称作 [垃圾回收器](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) 的东西在后台执行。它监控着所有对象的状态,并删除掉那些已经不可达的。 diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 5b732dee7c..a12402964b 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -9,52 +9,90 @@ 如果你才刚开始读此教程并学习 JavaScript,那可能还没接触到这个问题,但它却相当常见。 -例如,让我们考虑存储用户数据的对象。我们大多数用户的地址信息都存储在 `user.address` 属性中,街道信息存储在 `user.address.street` 属性中,但有些用户没有提供这些信息。 +举个例子,假设我们有很多个 `user` 对象,其中存储了我们的用户数据。 -在这种情况下,当我们尝试获取 `user.address.street` 时,将会收到错误信息: +我们大多数用户的地址都存储在 `user.address` 中,街道地址存储在 `user.address.street` 中,但有些用户没有提供这些信息。 + +在这种情况下,当我们尝试获取 `user.address.street`,而该用户恰好没提供地址信息,我们则会收到一个错误: ```js run -let user = {}; // 变量 user 没有 "address" 属性 +let user = {}; // 一个没有 "address" 属性的 user 对象 alert(user.address.street); // Error! ``` -这是预期的结果,JavaScript 的工作原理就是这样的,但是在很多实际场景中,我们更希望得到的是 `undefined`(表示没有 `street` 属性)而不是一个错误。 +这是预期的结果。JavaScript 的工作原理就是这样的。因为 `user.address` 为 `undefined`,尝试读取 `user.address.street` 会失败,并收到一个错误。 + +但是在很多实际场景中,我们更希望得到的是 `undefined`(表示没有 `street` 属性)而不是一个错误。 -……还有另一个例子。在 Web 开发中,我们可能需要获取页面上某个元素的有关信息,但有时该信息可能不存在: +……还有另一个例子。在 Web 开发中,我们可以使用特殊的方法调用(例如 `document.querySelector('.elem')`)以对象的形式获取一个网页元素,如果没有这种对象,则返回 `null`。 ```js run -// 如果 querySelector(...) 的结果为 null,则会报错 -let html = document.querySelector('.my-element').innerHTML; +// 如果 document.querySelector('.elem') 的结果为 null,则这里不存在这个元素 +let html = document.querySelector('.elem').innerHTML; // 如果 document.querySelector('.elem') 的结果为 null,则会出现错误 ``` -在 JavaScript 这门语言中出现 `?.` 前,`&&` 运算符常被用来解决这个问题。 +同样,如果该元素不存在,则访问 `null` 的 `.innerHTML` 时会出错。在某些情况下,当元素的缺失是没问题的时候,我们希望避免出现这种错误,而是接受 `html = null` 作为结果。 -例如: +我们如何实现这一点呢? + +可能最先想到的方案是在访问该值的属性之前,使用 `if` 或条件运算符 `?` 对该值进行检查,像这样: + +```js +let user = {}; + +alert(user.address ? user.address.street : undefined); +``` + +这样可以,这里就不会出现错误了……但是不够优雅。就像你所看到的,`"user.address"` 在代码中出现了两次。对于嵌套层次更深的属性就会出现更多次这样的重复,这就是问题了。 + +例如,让我们尝试获取 `user.address.street.name`。 + +我们既需要检查 `user.address`,又需要检查 `user.address.street`: + +```js +let user = {}; // user 没有 address 属性 + +alert(user.address ? user.address.street ? user.address.street.name : null : null); +``` + +这样就太扯淡了,并且这可能导致写出来的代码很难让别人理解。 + +甚至我们可以先忽略这个问题,因为我们有一种更好的实现方式,就是使用 `&&` 运算符: ```js run -let user = {}; // user 没有 address +let user = {}; // user 没有 address 属性 -alert( user && user.address && user.address.street ); // undefined(不报错) +alert( user.address && user.address.street && user.address.street.name ); // undefined(不报错) ``` -依次对整条路径上的属性使用与运算进行判断,以确保所有节点是存在的(如果不存在,则停止计算),但是写起来很麻烦。 +依次对整条路径上的属性使用与运算进行判断,以确保所有节点是存在的(如果不存在,则停止计算),但仍然不够优雅。 + +就像你所看到的,在代码中我们仍然重复写了好几遍对象属性名。例如在上面的代码中,`user.address` 被重复写了三遍。 + +这就是为什么可选链 `?.` 被加入到了 JavaScript 这门编程语言中。那就是彻底地解决以上所有问题! ## 可选链 -如果可选链 `?.` 前面部分是 `undefined` 或者 `null`,它会停止运算并返回 `undefined`。 +如果可选链 `?.` 前面的部分是 `undefined` 或者 `null`,它会停止运算并返回该部分。 **为了简明起见,在本文接下来的内容中,我们会说如果一个属性既不是 `null` 也不是 `undefined`,那么它就“存在”。** -下面这是一种安全地访问 `user.address.street` 的方式: +换句话说,例如 `value?.prop`: +- 如果 `value` 存在,则结果与 `value.prop` 相同, +- 否则(当 `value` 为 `undefined/null` 时)则返回 `undefined`。 + +下面这是一种使用 `?.` 安全地访问 `user.address.street` 的方式: ```js run -let user = {}; // user 没有 address +let user = {}; // user 没有 address 属性 -alert( user?.address?.street ); // undefined (不报错) +alert( user?.address?.street ); // undefined(不报错) ``` -以 `user?.address` 的方式来读取 `address` 是可行的,即使对象 `user` 不存在: +代码简洁明了,也不用重复写好几遍属性名。 + +即使 对象 `user` 不存在,使用 `user?.address` 来读取地址也没问题: ```js run let user = null; @@ -65,14 +103,12 @@ alert( user?.address.street ); // undefined 请注意:`?.` 语法使其前面的值成为可选值,但不会对其后面的起作用。 -在上面的例子中,`user?.` 只允许 `user` 为 `null/undefined`。 - -另一方面,如果 `user` 存在,那么它必须具有 `user.address` 属性,否则 `user?.address.street` 在第二个点符号处会报错。 +例如,在 `user?.address.street.name` 中,`?.` 允许 `user` 为 `null/undefined`,但仅此而已。更深层次的属性是通过常规方式访问的。如果我们希望它们中的一些也是可选的,那么我们需要使用更多的 `?.` 来替换 `.`。 ```warn header="不要过度使用可选链" 我们应该只将 `?.` 使用在一些东西可以不存在的地方。 -例如,如果根据我们的代码逻辑,`user` 对象必须存在,但 `address` 是可选的,那么 `user.address?.street` 会更好。 +例如,如果根据我们的代码逻辑,`user` 对象必须存在,但 `address` 是可选的,那么我们应该这样写 `user.address?.street`,而不是这样 `user?.address?.street`。 所以,如果 `user` 恰巧因为失误变为 undefined,我们会看到一个编程错误并修复它。否则,代码中的错误在不恰当的地方被消除了,这会导致调试更加困难。 ``` @@ -84,7 +120,7 @@ alert( user?.address.street ); // undefined // ReferenceError: user is not defined user?.address; ``` -`?.` 前的变量必须已声明(例如 `let/const/var user`)。可选链仅适用于已声明的变量。 +`?.` 前的变量必须已声明(例如 `let/const/var user` 或作为一个函数参数)。可选链仅适用于已声明的变量。 ```` ## 短路效应 @@ -113,17 +149,20 @@ alert(x); // 0,值没有增加 在下面这段代码中,有些用户具有 `admin` 方法,而有些没有: ```js run -let user1 = { +let userAdmin = { admin() { alert("I am admin"); } -} +}; -let user2 = {}; +let userGuest = {}; + +*!* +userAdmin.admin?.(); // I am admin +*/!* *!* -user1.admin?.(); // I am admin -user2.admin?.(); +userGuest.admin?.(); // 啥都没有(没有这样的方法) */!* ``` @@ -165,7 +204,7 @@ user?.name = "John"; // Error,不起作用 // 因为它在计算的是 undefined = "John" ``` -这不是那么聪明。 +这还不是那么智能。 ```` ## 总结 diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md index d26d605279..3bcf0ce310 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md @@ -2,7 +2,7 @@ importance: 5 --- -# 我能添加一个字符串属性吗? +# 我能为字符串添加一个属性吗? 思考下面的代码: diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index c70934276d..17a1930ac7 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -406,7 +406,7 @@ JavaScript 有一个内建的 [Math](https://developer.mozilla.org/en/docs/Web/J alert( Math.pow(2, 10) ); // 2 的 10 次幂 = 1024 ``` -`Math` 对象中还有更多函数和常量,包括三角函数,你可以在 [Math 函数文档](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) 中找到这些内容。 +`Math` 对象中还有更多函数和常量,包括三角函数,你可以在 [Math 对象文档](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) 中找到这些内容。 ## 总结 diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md index f893543e74..bbca63a320 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -30,8 +30,8 @@ let array = [ john ]; john = null; // 覆盖引用 *!* -// john 被存储在数组里, 所以它不会被垃圾回收机制回收 -// 我们可以通过 array[0] 来获取它 +// 前面由 john 所引用的那个对象被存储在了 array 中 +// 所以它不会被垃圾回收机制回收 */!* ``` @@ -48,7 +48,7 @@ map.set(john, "..."); john = null; // 覆盖引用 *!* -// john 被存储在 map 中, +// john 被存储在了 map 中, // 我们可以使用 map.keys() 来获取它 */!* ``` diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 513adbf1d9..c2d33275f2 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -188,7 +188,7 @@ alert( pow(2, 3) ); 当我们完成子调用后 —— 很容易恢复上一个上下文,因为它既保留了变量,也保留了当时所在代码的确切位置。 ```smart -在上面的图中,我们使用“行”一词作为示例,每一行只有一个子调用,但通常一行代码可能会包含多个子调用,像 `pow(…) + pow(…) + somethingElse(…)`。 +在上面的图中,我们使用“行(line)”一词,因为在我们的示例中,每一行只有一个子调用,但通常一行代码可能会包含多个子调用,例如 `pow(…) + pow(…) + somethingElse(…)`。 因此,更准确地说,执行是“在子调用之后立即恢复”的。 ``` diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index 09b3fe0325..6cbcadf061 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -82,7 +82,7 @@ function sayHi() { } sayHi(); -alert(phrase); // Error: phrase is not defined(检查开发者控制台) +alert(phrase); // Error: phrase is not defined ``` 可以看到,`var` 穿透了 `if`,`for` 和其它代码块。这是因为在早期的 JavaScript 中,块没有词法环境,而 `var` 就是这个时期的代表之一。 diff --git a/1-js/06-advanced-functions/05-global-object/article.md b/1-js/06-advanced-functions/05-global-object/article.md index 5401745af9..318b481baf 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -25,6 +25,8 @@ var gVar = 5; alert(window.gVar); // 5(成为了全局对象的属性) ``` +具有与函数声明相同的效果(在主代码流中具有 `function` 关键字的语句,而不是函数表达式)。 + 请不要依赖它!这种行为是出于兼容性而存在的。现代脚本通过使用 [JavaScript modules](info:modules) 来避免这种情况的发生。 如果我们使用 `let`,就不会发生这种情况: diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md index f77a22992d..f8bf4b6df2 100644 --- a/1-js/06-advanced-functions/06-function-object/article.md +++ b/1-js/06-advanced-functions/06-function-object/article.md @@ -347,6 +347,6 @@ welcome(); // Hello, Guest(嵌套调用有效) 此外,函数可以带有额外的属性。很多知名的 JavaScript 库都充分利用了这个功能。 -它们创建一个“主”函数,然后给它附加很多其它“辅助”函数。例如,[jQuery](https://jquery.com) 库创建了一个名为 `$` 的函数。[lodash](https://lodash.com) 库创建一个 `_` 函数,然后为其添加了 `_.add`、`_.keyBy` 以及其它属性(欲了解详情,参见 [docs](https://lodash.com/docs))。实际上,它们这么做是为了减少对全局空间的污染,这样一个库就只会有一个全局变量。这样就降低了命名冲突的可能性。 +它们创建一个“主”函数,然后给它附加很多其它“辅助”函数。例如,[jQuery](https://jquery.com) 库创建了一个名为 `$` 的函数。[lodash](https://lodash.com) 库创建一个 `_` 函数,然后为其添加了 `_.add`、`_.keyBy` 以及其它属性(想要了解更多内容,参查阅 [docs](https://lodash.com/docs))。实际上,它们这么做是为了减少对全局空间的污染,这样一个库就只会有一个全局变量。这样就降低了命名冲突的可能性。 所以,一个函数本身可以完成一项有用的工作,还可以在自身的属性中附带许多其他功能。 diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md index cb344d680e..2e51ee3307 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -281,7 +281,7 @@ setTimeout(function run() { 这个限制来自“远古时代”,并且许多脚本都依赖于此,所以这个机制也就存在至今。 -对于服务端的 JavaScript,就没有这个限制,并且还有其他调度即时异步任务的方式。例如 Node.js 的 [setImmediate](https://nodejs.org/api/timers.html)。因此,这个提醒只是针对浏览器环境的。 +对于服务端的 JavaScript,就没有这个限制,并且还有其他调度即时异步任务的方式。例如 Node.js 的 [setImmediate](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args)。因此,这个提醒只是针对浏览器环境的。 ```` ## 总结 diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index db6fa4cead..84b025d902 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -12,7 +12,7 @@ ![prototype](object-prototype-empty.svg) -原型有点“神奇”。当我们想要从 `object` 中读取一个缺失的属性时,JavaScript 会自动从原型中获取该属性。在编程中,这种行为被称为“原型继承”。许多炫酷的语言特性和编程技巧都基于此。 +当我们从 `object` 中读取一个缺失的属性时,JavaScript 会自动从原型中获取该属性。在编程中,这种行为被称为“原型继承”。很快,我们将通过很多示例来学习此类继承,以及基于此类继承的更炫酷的语言功能。 属性 `[[Prototype]]` 是内部的而且是隐藏的,但是这儿有很多设置它的方式。 @@ -27,19 +27,11 @@ let rabbit = { }; *!* -rabbit.__proto__ = animal; +rabbit.__proto__ = animal; // 设置 rabbit.[[Prototype]] = animal */!* ``` -```smart header="`__proto__` 是 `[[Prototype]]` 的因历史原因而留下来的 getter/setter" -请注意,`__proto__` 与 `[[Prototype]]` **不一样**。`__proto__` 是 `[[Prototype]]` 的 getter/setter。 - -`__proto__` 的存在是历史的原因。在现代编程语言中,将其替换为函数 `Object.getPrototypeOf/Object.setPrototypeOf` 也能 get/set 原型。我们稍后将学习造成这种情况的原因以及这些函数。 - -根据规范,`__proto__` 必须仅在浏览器环境下才能得到支持,但实际上,包括服务端在内的所有环境都支持它。目前,由于 `__proto__` 标记在观感上更加明显,所以我们在后面的示例中将使用它。 -``` - -如果我们在 `rabbit` 中查找一个缺失的属性,JavaScript 会自动从 `animal` 中获取它。 +现在,如果我们从 `rabbit` 中读取一个它没有的属性,JavaScript 会自动从 `animal` 中获取。 例如: @@ -130,6 +122,8 @@ alert(longEar.jumps); // true(从 rabbit) ![](proto-animal-rabbit-chain.svg) +现在,如果我们从 `longEar` 中读取一些它不存在的内容,JavaScript 会先在 `rabbit` 中查找,然后在 `animal` 中查找。 + 这里只有两个限制: 1. 引用不能形成闭环。如果我们试图在一个闭环中分配 `__proto__`,JavaScript 会抛出错误。 @@ -137,6 +131,19 @@ alert(longEar.jumps); // true(从 rabbit) 当然,这可能很显而易见,但是仍然要强调:只能有一个 `[[Prototype]]`。一个对象不能从其他两个对象获得继承。 + +```smart header="`__proto__` 是 `[[Prototype]]` 的因历史原因而留下来的 getter/setter" +初学者常犯一个普遍的错误,就是不知道 `__proto__` 和 `[[Prototype]]` 的区别。 + +请注意,`__proto__` 与内部的 `[[Prototype]]` **不一样**。`__proto__` 是 `[[Prototype]]` 的 getter/setter。稍后,我们将看到在什么情况下理解它们很重要,在建立对 JavaScript 语言的理解时,让我们牢记这一点。 + +`__proto__` 属性有点过时了。它的存在是出于历史的原因,现代编程语言建议我们应该使用函数 `Object.getPrototypeOf/Object.setPrototypeOf` 来取代 `__proto__` 去 get/set 原型。稍后我们将介绍这些函数。 + +根据规范,`__proto__` 必须仅受浏览器环境的支持。但实际上,包括服务端在内的所有环境都支持它,因此我们使用它是非常安全的。 + +由于 `__proto__` 标记在观感上更加明显,所以我们在后面的示例中将使用它。 +``` + ## 写入不使用原型 原型仅用于读取属性。 diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md index 2338818542..8203ccb2fb 100644 --- a/1-js/09-classes/01-class/1-rewrite-to-class/task.md +++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md @@ -4,6 +4,6 @@ importance: 5 # 重写为 class -`Clock` 类是以函数式编写的。请以 "class" 语法重写它。 +`Clock` 类(请见沙箱)是以函数式编写的。请以 "class" 语法重写它。 P.S. 时钟在控制台(console)中滴答,打开控制台即可查看。 diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index 50623a102b..516b12b66d 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -218,7 +218,7 @@ function makeClass(phrase) { return class { sayHi() { alert(phrase); - }; + } }; } diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index f4a06854d7..46cf2ca46a 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -76,8 +76,8 @@ Class `Rabbit` 的对象可以访问例如 `rabbit.hide()` 等 `Rabbit` 的方 ```js run function f(phrase) { return class { - sayHi() { alert(phrase) } - } + sayHi() { alert(phrase); } + }; } *!* @@ -300,7 +300,7 @@ alert(rabbit.earLength); // 10 ```js run class Animal { - name = 'animal' + name = 'animal'; constructor() { alert(this.name); // (*) diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md index 118baff90a..ade954394d 100644 --- a/1-js/09-classes/06-instanceof/article.md +++ b/1-js/09-classes/06-instanceof/article.md @@ -2,7 +2,7 @@ `instanceof` 操作符用于检查一个对象是否属于某个特定的 class。同时,它还考虑了继承。 -在许多情况下,可能都需要进行此类检查。在这儿,我们将使用它来构建一个 **多态性(polymorphic)** 的函数,该函数根据参数的类型对参数进行不同的处理。 +在许多情况下,可能都需要进行此类检查。例如,它可以被用来构建一个 **多态性(polymorphic)** 的函数,该函数根据参数的类型对参数进行不同的处理。 ## instanceof 操作符 [#ref-instanceof] diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index d2e10a6d8e..a4dd4b52ac 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -146,7 +146,7 @@ loadScript('/my/script.js', function(script) { }); */!* - }) + }); }); ``` @@ -223,7 +223,7 @@ loadScript('1.js', function(error, script) { }); } - }) + }); } }); ``` @@ -256,7 +256,7 @@ loadScript('1.js', function(error, script) { } }); } - }) + }); } }); --> @@ -296,7 +296,7 @@ function step3(error, script) { } else { // ...加载完所有脚本后继续 (*) } -}; +} ``` 看到了吗?它的作用相同,但是没有深层的嵌套了,因为我们将每个行为都编写成了一个独立的顶层函数。 diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index 6ce26a9301..a0f1ff1cb8 100644 --- a/1-js/11-async/03-promise-chaining/article.md +++ b/1-js/11-async/03-promise-chaining/article.md @@ -265,7 +265,7 @@ fetch('/article/promise-chaining/user.json') 现在,让我们用加载好的用户信息搞点事情。 -例如,我们可以多发一个到 GitHub 的请求,加载用户个人资料并显示头像: +例如,我们可以再向 GitHub 发送一个请求,加载用户个人资料并显示头像: ```js run // 发送一个对 user.json 的请求 diff --git a/1-js/11-async/05-promise-api/article.md b/1-js/11-async/05-promise-api/article.md index 563837f3f7..40a24c5f59 100644 --- a/1-js/11-async/05-promise-api/article.md +++ b/1-js/11-async/05-promise-api/article.md @@ -176,15 +176,14 @@ Promise.allSettled(urls.map(url => fetch(url))) 如果浏览器不支持 `Promise.allSettled`,很容易进行 polyfill: ```js -if(!Promise.allSettled) { - Promise.allSettled = function(promises) { - return Promise.all(promises.map(p => Promise.resolve(p).then(value => ({ - status: 'fulfilled', - value - }), reason => ({ - status: 'rejected', - reason - })))); +if (!Promise.allSettled) { + const rejectHandler = reason => ({ status: 'rejected', reason }); + + const resolveHandler = value => ({ status: 'fulfilled', value }); + + Promise.allSettled = function (promises) { + const convertedPromises = promises.map(p => Promise.resolve(p).then(resolveHandler, rejectHandler)); + return Promise.all(convertedPromises); }; } ``` diff --git a/1-js/11-async/06-promisify/article.md b/1-js/11-async/06-promisify/article.md index 75a5147dea..5c4334da65 100644 --- a/1-js/11-async/06-promisify/article.md +++ b/1-js/11-async/06-promisify/article.md @@ -4,6 +4,8 @@ 由于许多函数和库都是基于回调的,因此,在实际开发中经常会需要进行这种转换。因为使用 promise 更加方便,所以将基于回调的函数和库 promisify 是有意义的。(译注:promisify 即指 promise 化) +为了更好地理解,让我们来看一个例子。 + 例如,在 一章中我们有 `loadScript(src, callback)`。 ```js run @@ -21,35 +23,42 @@ function loadScript(src, callback) { // loadScript('path/script.js', (err, script) => {...}) ``` -让我们将其 promisify 吧。新的 `loadScriptPromise(src)` 将会达到同样的结果,但它只接受 `src`(没有回调)并返回 promise。 +该函数通过给定的 `src` 加载脚本,然后在出现错误时调用 `callback(err)`,或者在加载成功时调用 `callback(null, script)`。这是大家对于使用回调函数的共识,我们之前也学习过。 + +现在,让我们将其 promisify 吧。 + +我们将创建一个新的函数 `loadScriptPromise(src)`,与上面的函数作用相同(加载脚本),只是我们创建的这个函数会返回一个 promise 而不是使用回调。 + +换句话说,我们仅向它传入 `src`(没有 `callback`)并通过该函数的 return 获得一个 promise,当脚本加载成功时,该 promise 将以 `script` 为结果 resolve,否则将以出现的 error 为结果 reject。 +代码实现如下: ```js let loadScriptPromise = function(src) { return new Promise((resolve, reject) => { loadScript(src, (err, script) => { - if (err) reject(err) + if (err) reject(err); else resolve(script); }); - }) -} + }); +}; // 用法: // loadScriptPromise('path/script.js').then(...) ``` -现在,`loadScriptPromise` 非常适合基于 promise 的代码。 +正如我们所看到的,新的函数是对原始的 `loadScript` 函数的包装。新函数调用它,并提供了自己的回调来将其转换成 promise `resolve/reject`。 -正如我们所看到的,它将所有工作都委托给原始的 `loadScript`,并提供了转换成 promise `resolve/reject` 的自己的回调。 +现在 `loadScriptPromise` 非常适用于基于 promise 的代码了。如果我们相比于回调函数,更喜欢 promise(稍后我们将看到更多喜欢 promise 的原因),那么我们将改用它。 -在实际开发中,我们可能需要 promisify 很多函数,所以使用一个 helper 很有意义。我们将其称为 `promisify(f)`:它接受一个需要被 promisify 的函数 `f`,并返回一个包装(wrapper)函数。 +在实际开发中,我们可能需要 promisify 很多函数,所以使用一个 helper(辅助函数)很有意义。 -该包装(wrapper)函数的功能和上面的代码相同:返回一个 promise,将调用传递给原始的函数 `f`,并在自定义的回调中跟踪结果: +我们将其称为 `promisify(f)`:它接受一个需要被 promisify 的函数 `f`,并返回一个包装(wrapper)函数。 ```js function promisify(f) { - return function (...args) { // 返回一个包装函数(wrapper-function) + return function (...args) { // 返回一个包装函数(wrapper-function) (*) return new Promise((resolve, reject) => { - function callback(err, result) { // 我们对 f 的自定义的回调 + function callback(err, result) { // 我们对 f 的自定义的回调 (**) if (err) { reject(err); } else { @@ -62,18 +71,25 @@ function promisify(f) { f.call(this, ...args); // 调用原始的函数 }); }; -}; +} // 用法: let loadScriptPromise = promisify(loadScript); loadScriptPromise(...).then(...); ``` -这里我们假设,原始的函数期望一个带有两个参数 `(err, result)` 的回调。这就是我们最常遇到的形式。那么我们的自定义回调的格式完全正确,并且 `promisify` 在这种情况下非常有用。 +代码看起来可能有些复杂,但其本质与我们在上面写的那个是一样的,就是将 `loadScript` 函数 promisify。 + +调用 `promisify(f)` 会返回一个 `f` `(*)` 的包装器。该包装器返回一个 promise,并将调用转发给原始的 `f`,并在我们自定义的回调 `(**)` 中跟踪结果。 + +在这里,`promisify` 假设原始函数期望一个带有两个参数 `(err, result)` 的回调。这就是我们最常遇到的形式。那么我们自定义的回调的格式是完全正确的,在这种情况下 `promisify` 也可以完美地运行。 但是如果原始的 `f` 期望一个带有更多参数的回调 `callback(err, res1, res2, ...)`,该怎么办呢? -下面是 `promisify` 的更高级的版本:如果像这样进行调用 `promisify(f, true)`,那么 promise 的结果将是回调结果的数组 `[res1, res2, ...]`: +我们可以继续改进我们的辅助函数。让我们写一个更高阶版本的 `promisify`。 + +- 当它被以 `promisify(f)` 的形式调用时,它应该以与上面那个版本的实现的工作方式类似。 +- 当它被以 `promisify(f, true)` 的形式调用时,它应该返回以回调函数数组为结果 resolve 的 promise。这就是具有很多个参数的回调的结果。 ```js // promisify(f, true) 来获取结果数组 @@ -94,13 +110,15 @@ function promisify(f, manyArgs = false) { f.call(this, ...args); }); }; -}; +} // 用法: f = promisify(f, true); -f(...).then(arrayOfResults => ..., err => ...) +f(...).then(arrayOfResults => ..., err => ...); ``` +正如你所看到的,它与上面那个实现基本相同,只是根据 `manyArgs` 是否为真来决定仅使用一个还是所有参数调用 `resolve`。 + 对于一些更奇特的回调格式,例如根本没有 `err` 的格式:`callback(result)`,我们可以手动 promisify 这样的函数,而不使用 helper。 也有一些具有更灵活一点的 promisification 函数的模块(module),例如 [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify)。在 Node.js 中,有一个内建的 promisify 函数 `util.promisify`。 diff --git a/1-js/11-async/08-async-await/01-rewrite-async/task.md b/1-js/11-async/08-async-await/01-rewrite-async/task.md index a6280d2580..eae5676fa1 100644 --- a/1-js/11-async/08-async-await/01-rewrite-async/task.md +++ b/1-js/11-async/08-async-await/01-rewrite-async/task.md @@ -12,7 +12,7 @@ function loadJson(url) { } else { throw new Error(response.status); } - }) + }); } loadJson('no-such-user.json') diff --git a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md index a479994e54..0a7b404263 100644 --- a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md +++ b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md @@ -1,7 +1,7 @@ # 使用 async/await 重写 "rethrow" -下面你可以看到来自 一章的 "rethrow" 例子。让我们来用 `async/await` 重写它,而不是使用 `.then/catch`。 +下面你可以看到 "rethrow" 的例子。让我们来用 `async/await` 重写它,而不是使用 `.then/catch`。 同时,我们可以在 `demoGithubUser` 中使用循环以摆脱递归:在 `async/await` 的帮助下很容易实现。 @@ -22,7 +22,7 @@ function loadJson(url) { } else { throw new HttpError(response); } - }) + }); } // 询问用户名,直到 github 返回一个合法的用户 diff --git a/1-js/11-async/08-async-await/03-async-from-regular/task.md b/1-js/11-async/08-async-await/03-async-from-regular/task.md index 52c1785a51..cc04e121fb 100644 --- a/1-js/11-async/08-async-await/03-async-from-regular/task.md +++ b/1-js/11-async/08-async-await/03-async-from-regular/task.md @@ -1,7 +1,7 @@ # 在非 async 函数中调用 async 函数 -我们有一个“普通”函数。如何在这个函数中调用 `async` 函数并使用其结果? +我们有一个名为 `f` 的“普通”函数。你会怎样调用 `async` 函数 `wait()` 并在 `f` 中使用其结果? ```js async function wait() { @@ -11,7 +11,7 @@ async function wait() { } function f() { - // ...这里怎么写? + // ……这里你应该怎么写? // 我们需要调用 async wait() 并等待以拿到结果 10 // 记住,我们不能使用 "await" } diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md index 0962c07a62..c193ce55c6 100644 --- a/1-js/11-async/08-async-await/article.md +++ b/1-js/11-async/08-async-await/article.md @@ -156,7 +156,7 @@ class Thenable { // 1000ms 后使用 this.num*2 进行 resolve setTimeout(() => resolve(this.num * 2), 1000); // (*) } -}; +} async function f() { // 等待 1 秒,之后 result 变为 2 diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md index 7c1750c4a4..89e590b4f4 100644 --- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md +++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md @@ -363,7 +363,7 @@ async function* fetchCommits(repo) { - 初始 URL 是 `https://api.github.com/repos//commits`,并且下一页的 URL 将在响应的 `Link` header 中。 - `fetch` 方法允许我们提供授权和其他 header,如果需要 —— 这里 GitHub 需要的是 `User-Agent`。 2. commit 被以 JSON 的格式返回。 -3. 我们应该从响应(response)的 `Link` header 中获取前往下一页的 URL。它有一个特殊的格式,所以我们对它使用正则表达式 +3. 我们应该从响应(response)的 `Link` header 中获取前往下一页的 URL。它有一个特殊的格式,所以我们对它使用正则表达式(我们将在 [正则表达式](info:regular-expressions) 一章中学习它)。 - 前往下一页的 URL 看起来可能就像这样 `https://api.github.com/repositories/93253246/commits?page=2`。这是由 GitHub 自己生成的。 4. 然后,我们将接收到的所有 commit 一个一个地 yield 出来,当所有 commit 都 yield 完成时,将触发下一个 `while(url)` 迭代,并发出下一个请求。 diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index 5a59ea00ec..96df94cdca 100755 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -260,7 +260,7 @@ sayHi(); // Ready to serve, *!*Pete*/!*! diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 0fbd187335..8e892afeaa 100755 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -321,7 +321,7 @@ export {default as User} from './user.js'; // 重新导出 default 为什么要这样做?我们看一个实际开发中的用例。 -想象一下,我们正在编写一个 "package":一个包含大量模块的文件夹,其中一些功能是导出到外部的(像 NPM 这样的工具允许我们发布和分发这样的 package),并且其中一些模块仅仅是供其他 package 中的模块内部使用的 "helpers"。 +想象一下,我们正在编写一个 "package":一个包含大量模块的文件夹,其中一些功能是导出到外部的(像 NPM 这样的工具允许我们发布和分发这样的 package,但我们不是必须要去使用它们),并且其中一些模块仅仅是供其他 package 中的模块内部使用的 "helpers"。 文件结构可能是这样的: ``` @@ -378,7 +378,7 @@ export {default as User} from './user.js'; 重新导出时,默认导出需要单独处理。 -假设我们有 `user.js`,我们想从中重新导出类 `User`: +假设我们有一个 `user.js` 脚本,其中写了 `export default class User`,并且我们想重新导出类 `User`: ```js // 📁 user.js @@ -387,7 +387,9 @@ export default class User { } ``` -1. `export User from './user.js'` 无效。什么出了问题?这实际上是一个语法错误。 +我们可能会遇到两个问题: + +1. `export User from './user.js'` 无效。这会导致一个语法错误。 要重新导出默认导出,我们必须明确写出 `export {default as User}`,就像上面的例子中那样。 @@ -399,7 +401,7 @@ export default class User { export {default} from './user.js'; // 重新导出默认的导出 ``` -重新导出默认的导出的这种奇怪现象是某些开发者不喜欢它们的原因之一。 +重新导出一个默认导出的这种奇怪现象,是某些开发者不喜欢默认导出,而是喜欢命名的导出的原因之一。 ## 总结 diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md index 357a573134..9db69cb2fa 100644 --- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md +++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md @@ -19,5 +19,5 @@ function wrap(target) { user = wrap(user); alert(user.name); // John -alert(user.age); // ReferenceError: Property doesn't exist "age" +alert(user.age); // ReferenceError: Property doesn't exist: "age" ``` diff --git a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md index 9e7d24ac58..7e8b21ef05 100644 --- a/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md +++ b/1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md @@ -27,6 +27,6 @@ user = wrap(user); alert(user.name); // John *!* -alert(user.age); // ReferenceError: Property doesn't exist "age" +alert(user.age); // ReferenceError: Property doesn't exist: "age" */!* ``` diff --git a/1-js/99-js-misc/01-proxy/article.md b/1-js/99-js-misc/01-proxy/article.md index 6f56e4d959..b06fffbc39 100644 --- a/1-js/99-js-misc/01-proxy/article.md +++ b/1-js/99-js-misc/01-proxy/article.md @@ -437,7 +437,7 @@ user = { ``` -对 `user.checkPassword()` 的调用会调用被代理的对象 `user` 作为 `this`(点符号之前的对象会成为 `this`),因此,当它尝试访问 `this._password` 时,`get` 捕捉器将激活(在任何属性读取时,它都会被触发)并抛出错误。 +对 `user.checkPassword()` 的调用会将被代理的对象 `user` 作为 `this`(点符号之前的对象会成为 `this`),因此,当它尝试访问 `this._password` 时,`get` 捕捉器将激活(在任何属性读取时,它都会被触发)并抛出错误。 因此,我们在 `(*)` 行中将对象方法的上下文绑定到原始对象 `target`。然后,它们将来的调用将使用 `target` 作为 `this`,不会触发任何捕捉器。 diff --git a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md index 0f7a8f05c5..351b36b3de 100644 --- a/1-js/99-js-misc/04-reference-type/3-why-this/solution.md +++ b/1-js/99-js-misc/04-reference-type/3-why-this/solution.md @@ -5,7 +5,7 @@ 2. 同样,括号没有改变执行的顺序,点符号总是先执行。 -3. 这里我们有一个更复杂的 `(expression).method()` 调用。这个调用就像被分成了两行(代码)一样: +3. 这里我们有一个更复杂的 `(expression)()` 调用。这个调用就像被分成了两行(代码)一样: ```js no-beautify f = obj.go; // 计算函数表达式 @@ -14,7 +14,7 @@    这里的 `f()` 是作为一个没有(设定)`this` 的函数执行的。 -4. 与 `(3)` 相类似,在点符号 `.` 的左边也有一个表达式。 +4. 与 `(3)` 相类似,在括号 `()` 的左边也有一个表达式。 要解释 `(3)` 和 `(4)` 得到这种结果的原因,我们需要回顾一下属性访问器(点符号或方括号)返回的是引用类型的值。 diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md index 8ea7385a60..a6b1b11bf4 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -93,7 +93,7 @@ Reference Type 是一个特殊的“中间人”内部类型,目的是从 `.` 任何例如赋值 `hi = user.hi` 等其他的操作,都会将 Reference Type 作为一个整体丢弃掉,而会取 `user.hi`(一个函数)的值并继续传递。所以任何后续操作都“丢失”了 `this`。 -因此,`this` 的值仅在函数直接被通过点符号 `obj.method()` 或方括号 `obj['method']()` 语法(此处它们作用相同)调用时才被正确传递。在本教程的后续章节,我们会学习多种解决这个问题的方式,例如 [func.bind()](/bind#solution-2-bind)。 +因此,`this` 的值仅在函数直接被通过点符号 `obj.method()` 或方括号 `obj['method']()` 语法(此处它们作用相同)调用时才被正确传递。还有很多种解决这个问题的方式,例如 [func.bind()](/bind#solution-2-bind)。 ## 总结 diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index 008fc4d800..489e87bf54 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -363,7 +363,7 @@ document.getElementsByTagName('input')[0].value = 5; -目前为止,最常用的是 `querySelector` 和 `querySelectorAll`,但是 `getElementBy*` 可能会偶尔有用,或者可以在旧脚本中找到。 +目前为止,最常用的是 `querySelector` 和 `querySelectorAll`,但是 `getElement(s)By*` 可能会偶尔有用,或者可以在旧脚本中找到。 此外: diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md index b398b4b718..db7bc770c8 100644 --- a/2-ui/1-document/05-basic-dom-node-properties/article.md +++ b/2-ui/1-document/05-basic-dom-node-properties/article.md @@ -198,7 +198,7 @@ tagName 和 nodeName 之间有什么不同吗? ## innerHTML:内容 -[innerHTML](https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML) 属性允许将元素中的 HTML 获取为字符串形式。 +[innerHTML](https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin) 属性允许将元素中的 HTML 获取为字符串形式。 我们也可以修改它。因此,它是更改页面最有效的方法之一。 diff --git a/2-ui/1-document/06-dom-attributes-and-properties/article.md b/2-ui/1-document/06-dom-attributes-and-properties/article.md index 3c71e265e1..c07553f7a5 100644 --- a/2-ui/1-document/06-dom-attributes-and-properties/article.md +++ b/2-ui/1-document/06-dom-attributes-and-properties/article.md @@ -1,4 +1,3 @@ - # 特性和属性(Attributes and properties) 当浏览器加载页面时,它会“读取”(或者称之为:“解析”)HTML 并从中生成 DOM 对象。对于元素节点,大多数标准的 HTML 特性(attributes)会自动变成 DOM 对象的属性(properties)。(译注:attribute 和 property 两词意思相近,为作区分,全文将 attribute 译为“特性”,property 译为“属性”,请读者注意区分。) @@ -299,7 +298,7 @@ DOM 属性不总是字符串类型的。例如,`input.checked` 属性(对于 ``` -为什么使用特性比使用 `.order-state-new`,`.order-state-pending`,`order-state-canceled` 这些样式类要好? +为什么使用特性比使用 `.order-state-new`,`.order-state-pending`,`.order-state-canceled` 这些样式类要好? 因为特性值更容易管理。我们可以轻松地更改状态: diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index 861cb0b1f9..da1611d202 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -206,7 +206,7 @@ elem.addEventListener("click", e => alert(2)); - 然后,事件从文档根节点向下移动到 `event.target`,并在途中调用分配了 `addEventListener(..., true)` 的处理程序(`true` 是 `{capture: true}` 的一个简写形式)。 - 然后,在目标元素自身上调用处理程序。 -- 然后,事件从 `event.target` 冒泡到根,调用使用 `on` 和没有第三个参数的,或者第三个参数为 `false/{capture:false}` 的 `addEventListener` 分配的处理程序。 +- 然后,事件从 `event.target` 冒泡到根,调用使用 `on`、HTML 特性(attribute)和没有第三个参数的,或者第三个参数为 `false/{capture:false}` 的 `addEventListener` 分配的处理程序。 每个处理程序都可以访问 `event` 对象的属性: diff --git a/2-ui/2-events/03-event-delegation/article.md b/2-ui/2-events/03-event-delegation/article.md index a694af3a1a..572bdccba2 100644 --- a/2-ui/2-events/03-event-delegation/article.md +++ b/2-ui/2-events/03-event-delegation/article.md @@ -5,7 +5,7 @@ 这个想法是,如果我们有许多以类似方式处理的元素,那么就不必为每个元素分配一个处理程序 —— 而是将单个处理程序放在它们的共同祖先上。 -在处理程序中,我们获得 `event.target`,查看事件实际发生的位置并进行处理。 +在处理程序中,我们获取 `event.target` 以查看事件实际发生的位置并进行处理。 让我们看一个示例 —— 反映中国古代哲学的 [八卦图](http://en.wikipedia.org/wiki/Ba_gua)。 diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 63ee8fef96..7804c9dce8 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -145,7 +145,7 @@ let analyticsData = { /* 带有收集的数据的对象 */ }; window.addEventListener("unload", function() { navigator.sendBeacon("/analytics", JSON.stringify(analyticsData)); -}; +}); ``` - 请求以 POST 方式发送。 diff --git a/README.md b/README.md index da7b8a5386..1cdfd98cd5 100755 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ - **QQ 群**:打开 QQ 搜索群号 **`866757202`** 或 [扫二维码](https://user-images.githubusercontent.com/26959437/64609229-12f9e900-d3ff-11e9-96e8-147335f5e264.jpg),验证信息填写 **`JS 教程`**。 -本项目托管了现代 JavaScript 教程中文版的内容,该内容发布在 [https://zh.javascript.info](https://zh.javascript.info) +本项目托管了现代 JavaScript 教程中文版的内容,此内容发布在 [https://zh.javascript.info](https://zh.javascript.info)