diff --git a/1-js/02-first-steps/16-arrow-functions-basics/article.md b/1-js/02-first-steps/16-arrow-functions-basics/article.md index e96481cf3a..0d61cd2627 100644 --- a/1-js/02-first-steps/16-arrow-functions-basics/article.md +++ b/1-js/02-first-steps/16-arrow-functions-basics/article.md @@ -67,7 +67,7 @@ let welcome = (age < 18) ? () => alert('Hello') : () => alert("Greetings!"); -welcome(); // 现在好了 +welcome(); ``` 一开始,箭头函数可能看起来并不熟悉,也不容易读懂,但一旦我们看习惯了之后,这种情况很快就会改变。 diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md index 1a5e35a7ac..b4ad6ea118 100644 --- a/1-js/03-code-quality/03-comments/article.md +++ b/1-js/03-code-quality/03-comments/article.md @@ -125,25 +125,25 @@ function addJuice(container) { 记录函数的参数和用法 : 有一个专门用于记录函数的语法 [JSDoc](http://en.wikipedia.org/wiki/JSDoc):用法、参数和返回值。 - 例如: - ```js - /** - * 返回 x 的 n 次幂的值。 - * - * @param {number} x 要改变的值。 - * @param {number} n 幂数,必须是一个自然数。 - * @return {number} x 的 n 次幂的值。 - */ - function pow(x, n) { - ... - } - ``` +例如: +```js +/** + * 返回 x 的 n 次幂的值。 + * + * @param {number} x 要改变的值。 + * @param {number} n 幂数,必须是一个自然数。 + * @return {number} x 的 n 次幂的值。 + */ +function pow(x, n) { + ... +} +``` - 这种注释可以帮助我们理解函数的目的,并且不需要研究其内部的实现代码,就可以直接正确地使用它。 +这种注释可以帮助我们理解函数的目的,并且不需要研究其内部的实现代码,就可以直接正确地使用它。 - 顺便说一句,很多诸如 [WebStorm](https://www.jetbrains.com/webstorm/) 这样的编辑器,都可以很好地理解和使用这些注释,来提供自动补全和一些自动化代码检查工作。 +顺便说一句,很多诸如 [WebStorm](https://www.jetbrains.com/webstorm/) 这样的编辑器,都可以很好地理解和使用这些注释,来提供自动补全和一些自动化代码检查工作。 - 当然,也有一些像 [JSDoc 3](https://github.com/jsdoc3/jsdoc) 这样的工具,可以通过注释直接生成 HTML 文档。你可以在 阅读更多关于 JSDoc 的信息。 +当然,也有一些像 [JSDoc 3](https://github.com/jsdoc3/jsdoc) 这样的工具,可以通过注释直接生成 HTML 文档。你可以在 阅读更多关于 JSDoc 的信息。 为什么任务以这种方式解决? : 写了什么代码很重要。但是为什么 **不** 那样写可能对于理解正在发生什么更重要。为什么任务是通过这种方式解决的?代码并没有给出答案。 diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 8d215ba7e7..192ed762c3 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -215,7 +215,7 @@ let bag = { function makeUser(name, age) { return { name: name, - age: age + age: age, // ……其他的属性 }; } @@ -233,7 +233,7 @@ function makeUser(name, age) { *!* return { name, // 与 name: name 相同 - age // 与 age: age 相同 + age, // 与 age: age 相同 // ... }; */!* diff --git a/1-js/05-data-types/11-date/8-format-date-relative/solution.md b/1-js/05-data-types/11-date/8-format-date-relative/solution.md index eb5fce1b17..cf80e0cddf 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/solution.md +++ b/1-js/05-data-types/11-date/8-format-date-relative/solution.md @@ -40,7 +40,7 @@ alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 sec. ago" alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 min. ago" -// 昨天的日期如:31.12.2016, 20:00 +// 昨天的日期如:31.12.2016 20:00 alert( formatDate(new Date(new Date - 86400 * 1000)) ); ``` diff --git a/1-js/05-data-types/11-date/8-format-date-relative/task.md b/1-js/05-data-types/11-date/8-format-date-relative/task.md index 1ae208297b..5dd110efb2 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/task.md +++ b/1-js/05-data-types/11-date/8-format-date-relative/task.md @@ -20,6 +20,6 @@ alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 sec. ago" alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 min. ago" -// yesterday's date like 31.12.16, 20:00 +// 昨天的日期,例如 31.12.16 20:00 alert( formatDate(new Date(new Date - 86400 * 1000)) ); ``` diff --git a/1-js/08-prototypes/02-function-prototype/article.md b/1-js/08-prototypes/02-function-prototype/article.md index eaf302c590..2ec90a2895 100644 --- a/1-js/08-prototypes/02-function-prototype/article.md +++ b/1-js/08-prototypes/02-function-prototype/article.md @@ -41,7 +41,7 @@ alert( rabbit.eats ); // true 在上图中,`"prototype"` 是一个水平箭头,表示一个常规属性,`[[Prototype]]` 是垂直的,表示 `rabbit` 继承自 `animal`。 ```smart header="`F.prototype` 仅用在 `new F` 时" -`F.prototype` 属性仅在 `new F` 被调用时使用,它为新对象的 `[[Prototype]]` 赋值。之后,`F.prototype` 和新对象之间就没有任何联系了。可以把它看成“一次性的礼物”。 +`F.prototype` 属性仅在 `new F` 被调用时使用,它为新对象的 `[[Prototype]]` 赋值。 如果在创建之后,`F.prototype` 属性有了变化(`F.prototype = `),那么通过 `new F` 创建的新对象也将随之拥有新的对象作为 `[[Prototype]]`,但已经存在的对象将保持旧有的值。 ``` diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index 0a34e017c0..7e20268ab9 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -215,11 +215,39 @@ alert( new PropertyRequiredError("field").name ); // PropertyRequiredError 在上面代码中的函数 `readUser` 的目的就是“读取用户数据”。在这个过程中可能会出现不同类型的 error。目前我们有了 `SyntaxError` 和 `ValidationError`,但是将来,函数 `readUser` 可能会不断壮大,并可能会产生其他类型的 error。 -调用 `readUser` 的代码应该处理这些 error。现在它在 `catch` 块中使用了多个 `if` 语句来检查 error 类,处理已知的 error,并再次抛出未知的 error。但是如果函数 `readUser` 产生了多种 error,那么我们应该扪心自问:我们真的想在每个调用 `readUser` 的代码中都一一检查所有的 error 类型吗? +调用 `readUser` 的代码应该处理这些 error。现在它在 `catch` 块中使用了多个 `if` 语句来检查 error 类,处理已知的 error,并再次抛出未知的 error。 -通常答案是 "No":外部代码希望“比它高一个级别”,外部代码只想具有几种“数据读取异常” — 为什么发生了这样的 error 通常是无关紧要的(error 信息描述了它)。或者,如果能有一种方法能够获取 error 的详细信息那就更好了,但前提是我们需要这样做。 +该方案是这样的: -因此,让我们创建一个新的类 `ReadError` 来表示此类 error。如果在 `readUser` 内部发生了 error,我们将在那里捕获这个 error 并生成 `ReadError`。我们也会在其 `cause` 属性中保留对原始 error 的引用。然后,外部代码将只需要检查 `ReadError`。 +```js +try { + ... + readUser() // 潜在的 error 源 + ... +} catch (err) { + if (err instanceof ValidationError) { + // 处理 validation error + } else if (err instanceof SyntaxError) { + // 处理 syntax error + } else { + throw err; // 未知 error,再次抛出它 + } +} +``` + +在上面的代码中,我们可以看到两种类型的 error,但是可以有更多。 + +如果 `readUser` 函数会产生多种 error,那么我们应该问问自己:我们是否真的想每次都一一检查所有的 error 类型? + +通常答案是 "No":我们希望能够“比它高一个级别”。我们只想知道这里是否是“数据读取异常” — 为什么发生了这样的 error 通常是无关紧要的(error 信息描述了它)。或者,如果我们有一种方法能够获取 error 的详细信息那就更好了,但前提是我们需要。 + +我们所描述的这项技术被称为“包装异常”。 + +1. 我们将创建一个新的类 `ReadError` 来表示一般的“数据读取” error。 +2. 函数`readUser` 将捕获内部发生的数据读取 error,例如 `ValidationError` 和 `SyntaxError`,并生成一个 `ReadError` 来进行替代。 +3. 对象 `ReadError` 会把对原始 error 的引用保存在其 `cause` 属性中。 + +之后,调用 `readUser` 的代码只需要检查 `ReadError`,而不必检查每种数据读取 error。并且,如果需要更多 error 细节,那么可以检查 `readUser` 的 `cause` 属性。 下面的代码定义了 `ReadError`,并在 `readUser` 和 `try..catch` 中演示了其用法: @@ -293,7 +321,7 @@ try { 所以外部代码检查 `instanceof ReadError`,并且它的确是。不必列出所有可能的 error 类型。 -这种方法被称为“包装异常(wrapping exceptions)”,因为我们将“低级别的异常”包装到 `ReadError` 中,这对于调用代码来说更加抽象和方便。它被广泛应用于面向对象的编程中。 +这种方法被称为“包装异常(wrapping exceptions)”,因为我们将“低级别”的异常“包装”到了更抽象的 `ReadError` 中。它被广泛应用于面向对象的编程中。 ## 总结 diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index 50e7171a9a..07a6163d4d 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -10,11 +10,11 @@ 但是,我们会尽全力使讲解变得更加清晰。在这儿不会有浏览器方面的真正复杂的东西。 ``` -JavaScipt 中的许多行为(action)都是 **异步的**。换句话说,我们现在启动它们,但在稍后再完成。 +JavaScipt 主机(host)环境提供了许多函数,这些函数允许我们安排 **异步** 动作(action)。换句话说,我们现在开始执行的动作,但它们会在稍后完成。 -例如,我们可以使用 `setTimeout` 来安排此类行为。 +例如,`setTimeout` 函数就是一个这样的函数。 -这儿有一些实际中的异步行为的示例,例如加载脚本和模块(我们将在后面的章节中介绍)。 +这儿有一些实际中的异步动作的示例,例如加载脚本和模块(我们将在后面的章节中介绍)。 让我们看一下函数 `loadScript(src)`,该函数使用给定的 `src` 加载脚本: @@ -263,7 +263,7 @@ loadScript('1.js', function(error, script) { ![](callback-hell.svg) -嵌套调用的“金字塔”随着每个异步行为会向右增长。很快它就失控了。 +嵌套调用的“金字塔”随着每个异步动作会向右增长。很快它就失控了。 所以这种编码方式不是很好。 @@ -307,4 +307,4 @@ function step3(error, script) { 我们希望还有更好的方法。 -幸运地是,有其他方法可以避免此类金字塔。最好的方法之一就是 "promise",我们将在下一章中介绍它。 +幸运的是,有其他方法可以避免此类金字塔。最好的方法之一就是 "promise",我们将在下一章中介绍它。 diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html index ca9c4d579b..8f855ecfa0 100755 --- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html +++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html @@ -9,7 +9,7 @@ background-color: #00FF00; position: relative; } - + #ball { position: absolute; } @@ -20,7 +20,7 @@
- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -38,4 +38,4 @@ - \ No newline at end of file + diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md index 64cec9e67d..4caa2e5983 100644 --- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md +++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md @@ -1,4 +1,4 @@ -小球具有 `position:absolute`。这意味着它的 `left/top` 坐标是从最近的具有定位属性的元素开始测量的,这个元素即 `#field`(因为它有 `position:relative`)。 +球具有 `position:absolute`。这意味着它的 `left/top` 坐标是从最近的具有定位属性的元素开始测量的,这个元素即 `#field`(因为它有 `position:relative`)。 坐标从场(field)的左上角内侧开始: @@ -24,17 +24,22 @@ ball.style.left = Math.round(field.clientWidth / 2 - ball.offsetWidth / 2) + 'px ball.style.top = Math.round(field.clientHeight / 2 - ball.offsetHeight / 2) + 'px'; ``` -**注意:陷阱!** +现在,球终于居中了。 + +````warn header="注意:陷阱!" 当 `` 没有 width/height 时,代码将无法可靠地工作: ```html ``` +```` 当浏览器不知道图片的 width/height(通过标签 attribute 或 CSS)时,它会假定它们等于 `0`,直到图片加载完成。 -但在实际中,第一次加载后,浏览器通常会缓存该图片,并在下一次加载时,浏览器会立即拥有该图片的大小。但是在第一次加载时, `ball.offsetWidth` 的值为 `0`,这会导致错误的坐标。 +因此,在图片加载完成之前,`ball.offsetWidth` 的值为 `0`。这会导致上面的代码中会有错误的坐标。 + +在第一次加载完成后,浏览器通常会缓存该图片,并在下一次加载时,浏览器会立即拥有该图片的大小。但是在第一次加载时,`ball.offsetWidth` 的值为 `0`。 我们应该通过在 `` 中添加 `width/height` 来解决这个问题: diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html index 9ebe6001e7..9f21e54212 100755 --- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html +++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html @@ -26,7 +26,7 @@