diff --git a/README.MD b/README.MD index d7803a05db..8ee2bf0b04 100644 --- a/README.MD +++ b/README.MD @@ -26,6 +26,7 @@ ## 上新推荐 🎉 +* `v1.4.x`:新增了文章内容区块的 [背景底纹配置](https://xugaoyi.github.io/vuepress-theme-vdoing-doc/pages/a20ce8/#文章内容块的背景底纹),可以让你的文章看起来像笔记本的风格哟~(2020.07.30) * `v1.2.x`:这个版本对整体的UI细节做了很多优化,比如标签栏和分类栏等 (2020.06.09) * `v1.1.x`:从这个版本开始主题新增了两个`超好用`、`高颜值`的Markdown容器,快去 [体验](https://xugaoyi.github.io/vuepress-theme-vdoing-doc/pages/d0d7eb) 吧~ (2020.05.29) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a9e3d80e75..ade2d07f7f 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -34,24 +34,28 @@ module.exports = { // tag: false, // 是否打开标签功能,默认true。 如打开,会做的事情有:1. 自动生成的frontmatter包含标签字段 2.页面中显示与标签相关的信息和模块 3.自动生成标签页面(在@pages文件夹)。如关闭,则反之。 // archive: false, // 是否打开归档功能,默认true。 如打开,会做的事情有:1.自动生成归档页面(在@pages文件夹)。如关闭,则反之。 // categoryText: '随笔', // 碎片化文章(_posts文件夹的文章)预设生成的分类值,默认'随笔' + // bodyBgImg: [ // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175828.jpeg', // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175845.jpeg', // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175846.jpeg' // ], // body背景大图,默认无。 单张图片 String || 多张图片 Array, 多张图片时每隔15秒换一张。 + // bodyBgImgOpacity: 0.5, // body背景图透明度,选值 0 ~ 1.0, 默认0.5 + // titleBadge: false, // 文章标题前的图标是否显示,默认true // titleBadgeIcons: [ // 文章标题前图标的地址,默认主题内置图标 // '图标地址1', // '图标地址2' // ], + contentBgStyle: 1, // 文章内容块的背景风格,默认无. 1 => 方格 | 2 => 横线 | 3 => 竖线 | 4 => 左斜线 | 5 => 右斜线 | 6 => 点状 - sidebar: 'structuring', // 侧边栏 'structuring' | { mode: 'structuring', collapsable: Boolean} | 'auto' | 自定义 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页 - - // sidebarOpen: false, // 初始状态是否打开侧边栏,默认true // updateBar: { // 最近更新栏 // showToArticle: true, // 显示到文章页底部,默认true // moreArticle: '/archives' // “更多文章”跳转的页面,默认'/archives' // }, + // sidebarOpen: false, // 初始状态是否打开侧边栏,默认true + + sidebar: 'structuring', // 侧边栏 'structuring' | { mode: 'structuring', collapsable: Boolean} | 'auto' | 自定义 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页 author: { // 文章默认的作者信息,可在md文件中单独配置此信息 String | {name: String, link: String} name: 'Evan Xu', // 必需 diff --git "a/docs/06.\346\224\266\350\227\217\345\244\271/01.\347\275\221\347\253\231.md" "b/docs/06.\346\224\266\350\227\217\345\244\271/01.\347\275\221\347\253\231.md" index deca5a46d5..1b6502bcd9 100644 --- "a/docs/06.\346\224\266\350\227\217\345\244\271/01.\347\275\221\347\253\231.md" +++ "b/docs/06.\346\224\266\350\227\217\345\244\271/01.\347\275\221\347\253\231.md" @@ -92,7 +92,7 @@ article: false * [CSS3-Box Shadow(阴影)](https://www.html.cn/tool/css3Preview/Box-Shadow.html) * [贝塞尔曲线生成器 ](https://cubic-bezier.com) * [花纹背景生成器](http://www.heropatterns.com/) -* [花纹背景css](https://github.com/bansal-io/pattern.css) +* [花纹背景-pattern.css](https://github.com/bansal-io/pattern.css) ### CDN加速 * [jsDelivr](http://www.jsdelivr.com/) 国外的一家优秀的公共 CDN 服务提供商 diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/16.Promise \345\257\271\350\261\241.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/16.Promise \345\257\271\350\261\241.md" index 9272030b1c..5e36cf6d94 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/16.Promise \345\257\271\350\261\241.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/16.Promise \345\257\271\350\261\241.md" @@ -16,23 +16,23 @@ Promise 是异步编程的一种解决方案,比传统的解决方案——回 所谓`Promise`,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。 -`Promise`对象有以下两个特点。 +`Promise`对象有以下**两个特点**。 -(1)对象的状态不受外界影响。`Promise`对象代表一个异步操作,有三种状态:`pending`(进行中)、`fulfilled`(已成功)和`rejected`(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是`Promise`这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。 +(1)**对象的状态不受外界影响**。`Promise`对象代表一个异步操作,有三种状态:`pending`(进行中)、`fulfilled`(已成功)和`rejected`(已失败)。**只有异步操作的结果,可以决定当前是哪一种状态**,任何其他操作都无法改变这个状态。这也是`Promise`这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。 -(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。`Promise`对象的状态改变,只有两种可能:从`pending`变为`fulfilled`和从`pending`变为`rejected`。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对`Promise`对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。 +(2)**一旦状态改变,就不会再变,任何时候都可以得到这个结果**。`Promise`对象的状态改变,只有两种可能:从`pending`变为`fulfilled`和从`pending`变为`rejected`。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对`Promise`对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。 注意,为了行文方便,本章后面的`resolved`统一只指`fulfilled`状态,不包含`rejected`状态。 有了`Promise`对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,`Promise`对象提供统一的接口,使得控制异步操作更加容易。 -`Promise`也有一些缺点。首先,无法取消`Promise`,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,`Promise`内部抛出的错误,不会反应到外部。第三,当处于`pending`状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 +`Promise`也有一些缺点。首先,**无法取消`Promise`,一旦新建它就会立即执行,无法中途取消**。其次,**如果不设置回调函数,`Promise`内部抛出的错误,不会反应到外部**。第三,**当处于`pending`状态时,无法得知目前进展到哪一个阶段**(刚刚开始还是即将完成)。 如果某些事件不断地反复发生,一般来说,使用 [Stream](https://nodejs.org/api/stream.html) 模式是比部署`Promise`更好的选择。 ## 基本用法 -ES6 规定,`Promise`对象是一个构造函数,用来生成`Promise`实例。 +ES6 规定,**`Promise`对象是一个构造函数,用来生成`Promise`实例**。 下面代码创造了一个`Promise`实例。 @@ -48,11 +48,11 @@ const promise = new Promise(function(resolve, reject) { }); ``` -`Promise`构造函数接受一个函数作为参数,该函数的两个参数分别是`resolve`和`reject`。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。 +`Promise`构造函数接受一个函数作为参数,该**函数的两个参数分别是`resolve`和`reject`。它们是两个函数**,由 JavaScript 引擎提供,不用自己部署。 `resolve`函数的作用是,将`Promise`对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;`reject`函数的作用是,将`Promise`对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。 -`Promise`实例生成以后,可以用`then`方法分别指定`resolved`状态和`rejected`状态的回调函数。 +**`Promise`实例生成以后,可以用`then`方法分别指定`resolved`状态和`rejected`状态的回调函数。** ```javascript promise.then(function(value) { @@ -62,7 +62,7 @@ promise.then(function(value) { }); ``` -`then`方法可以接受两个回调函数作为参数。第一个回调函数是`Promise`对象的状态变为`resolved`时调用,第二个回调函数是`Promise`对象的状态变为`rejected`时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受`Promise`对象传出的值作为参数。 +`then`方法可以接受两个回调函数作为参数。第一个回调函数是`Promise`对象的状态变为`resolved`时调用,第二个回调函数是`Promise`对象的状态变为`rejected`时调用。其中,**第二个函数是可选的**,不一定要提供。这**两个函数都接受`Promise`对象传出的值作为参数**。 下面是一个`Promise`对象的简单例子。 @@ -80,7 +80,7 @@ timeout(100).then((value) => { 上面代码中,`timeout`方法返回一个`Promise`实例,表示一段时间以后才会发生的结果。过了指定的时间(`ms`参数)以后,`Promise`实例的状态变为`resolved`,就会触发`then`方法绑定的回调函数。 -Promise 新建后就会立即执行。 +**Promise 新建后就会立即执行**。 ```javascript let promise = new Promise(function(resolve, reject) { @@ -99,7 +99,7 @@ console.log('Hi!'); // resolved ``` -上面代码中,Promise 新建后立即执行,所以首先输出的是`Promise`。然后,`then`方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以`resolved`最后输出。 +上面代码中,**Promise 新建后立即执行**,所以首先输出的是`Promise`。然后,**`then`方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行**,所以`resolved`最后输出。 下面是异步加载图片的例子。 @@ -174,7 +174,7 @@ const p2 = new Promise(function (resolve, reject) { 上面代码中,`p1`和`p2`都是 Promise 的实例,但是`p2`的`resolve`方法将`p1`作为参数,即一个异步操作的结果是返回另一个异步操作。 -注意,这时`p1`的状态就会传递给`p2`,也就是说,`p1`的状态决定了`p2`的状态。如果`p1`的状态是`pending`,那么`p2`的回调函数就会等待`p1`的状态改变;如果`p1`的状态已经是`resolved`或者`rejected`,那么`p2`的回调函数将会立刻执行。 +**注意**,**这时`p1`的状态就会传递给`p2`,也就是说,`p1`的状态决定了`p2`的状态**。如果`p1`的状态是`pending`,那么`p2`的回调函数就会等待`p1`的状态改变;如果`p1`的状态已经是`resolved`或者`rejected`,那么`p2`的回调函数将会立刻执行。 ```javascript const p1 = new Promise(function (resolve, reject) { @@ -191,9 +191,9 @@ p2 // Error: fail ``` -上面代码中,`p1`是一个 Promise,3 秒之后变为`rejected`。`p2`的状态在 1 秒之后改变,`resolve`方法返回的是`p1`。由于`p2`返回的是另一个 Promise,导致`p2`自己的状态无效了,由`p1`的状态决定`p2`的状态。所以,后面的`then`语句都变成针对后者(`p1`)。又过了 2 秒,`p1`变为`rejected`,导致触发`catch`方法指定的回调函数。 +上面代码中,`p1`是一个 Promise,3 秒之后变为`rejected`。`p2`的状态在 1 秒之后改变,`resolve`方法返回的是`p1`。由于`p2`返回的是另一个 Promise,导致`p2`自己的状态无效了,由`p1`的状态决定`p2`的状态。所以,**后面的`then`语句都变成针对后者(`p1`)**。又过了 2 秒,`p1`变为`rejected`,导致触发`catch`方法指定的回调函数。 -注意,调用`resolve`或`reject`并不会终结 Promise 的参数函数的执行。 +注意,**调用`resolve`或`reject`并不会终结 Promise 的参数函数的执行**。 ```javascript new Promise((resolve, reject) => { @@ -208,7 +208,7 @@ new Promise((resolve, reject) => { 上面代码中,调用`resolve(1)`以后,后面的`console.log(2)`还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。 -一般来说,调用`resolve`或`reject`以后,Promise 的使命就完成了,后继操作应该放到`then`方法里面,而不应该直接写在`resolve`或`reject`的后面。所以,最好在它们前面加上`return`语句,这样就不会有意外。 +一般来说,调用`resolve`或`reject`以后,Promise 的使命就完成了,后继操作应该放到`then`方法里面,而不应该直接写在`resolve`或`reject`的后面。所以,**最好在它们前面加上`return`语句**,这样就不会有意外。 ```javascript new Promise((resolve, reject) => { @@ -220,19 +220,19 @@ new Promise((resolve, reject) => { ## Promise.prototype.then() -Promise 实例具有`then`方法,也就是说,`then`方法是定义在原型对象`Promise.prototype`上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,`then`方法的第一个参数是`resolved`状态的回调函数,第二个参数(可选)是`rejected`状态的回调函数。 +Promise 实例具有`then`方法,也就是说,`then`方法是定义在原型对象`Promise.prototype`上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,**`then`方法的第一个参数是`resolved`状态的回调函数,第二个参数(可选)是`rejected`状态的回调函数。** -`then`方法返回的是一个新的`Promise`实例(注意,不是原来那个`Promise`实例)。因此可以采用链式写法,即`then`方法后面再调用另一个`then`方法。 +**`then`方法返回的是一个新的`Promise`实例(注意,不是原来那个`Promise`实例)**。因此可以采用链式写法,即`then`方法后面再调用另一个`then`方法。 ```javascript getJSON("/posts.json").then(function(json) { return json.post; -}).then(function(post) { +}).then(function(post) { // 这里的post是前面一个then返回的参数 // ... }); ``` -上面的代码使用`then`方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。 +上面的代码使用`then`方法,依次指定了两个回调函数。**第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。** 采用链式的`then`,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个`Promise`对象(即有异步操作),这时后一个回调函数,就会等待该`Promise`对象的状态发生变化,才会被调用。 @@ -350,7 +350,7 @@ getJSON('/post/1.json').then(function(post) { 上面代码中,一共有三个 Promise 对象:一个由`getJSON`产生,两个由`then`产生。它们之中任何一个抛出的错误,都会被最后一个`catch`捕获。 -一般来说,不要在`then`方法里面定义 Reject 状态的回调函数(即`then`的第二个参数),总是使用`catch`方法。 +**一般来说,不要在`then`方法里面定义 Reject 状态的回调函数(即`then`的第二个参数),总是使用`catch`方法。** ```javascript // bad @@ -371,7 +371,7 @@ promise }); ``` -上面代码中,第二种写法要好于第一种写法,理由是第二种写法可以捕获前面`then`方法执行中的错误,也更接近同步的写法(`try/catch`)。因此,建议总是使用`catch`方法,而不使用`then`方法的第二个参数。 +上面代码中,第二种写法要好于第一种写法,理由是第二种写法可以捕获前面`then`方法执行中的错误,也更接近同步的写法(`try/catch`)。因此,**建议总是使用`catch`方法,而不使用`then`方法的第二个参数**。 跟传统的`try/catch`代码块不同的是,如果没有使用`catch`方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。 @@ -388,11 +388,11 @@ someAsyncThing().then(function() { }); setTimeout(() => { console.log(123) }, 2000); -// Uncaught (in promise) ReferenceError: x is not defined +// Uncaught (in promise) ReferenceError: x is not defined // 报错却不退出进程 // 123 ``` -上面代码中,`someAsyncThing`函数产生的 Promise 对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示`ReferenceError: x is not defined`,但是不会退出进程、终止脚本执行,2 秒之后还是会输出`123`。这就是说,Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。 +上面代码中,`someAsyncThing`函数产生的 Promise 对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示`ReferenceError: x is not defined`,但是不会退出进程、终止脚本执行,2 秒之后还是会输出`123`。这就是说,**Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”**。 这个脚本放在服务器执行,退出码就是`0`(即表示执行成功)。不过,Node 有一个`unhandledRejection`事件,专门监听未捕获的`reject`错误,上面的脚本会触发这个事件的监听函数,可以在监听函数里面抛出错误。 @@ -420,7 +420,7 @@ promise.then(function (value) { console.log(value) }); 上面代码中,Promise 指定在下一轮“事件循环”再抛出错误。到了那个时候,Promise 的运行已经结束了,所以这个错误是在 Promise 函数体外抛出的,会冒泡到最外层,成了未捕获的错误。 -一般总是建议,Promise 对象后面要跟`catch`方法,这样可以处理 Promise 内部发生的错误。`catch`方法返回的还是一个 Promise 对象,因此后面还可以接着调用`then`方法。 +一般总是建议,Promise 对象后面要跟`catch`方法,这样可以处理 Promise 内部发生的错误。**`catch`方法返回的还是一个 Promise 对象**,因此后面还可以接着调用`then`方法。 ```javascript const someAsyncThing = function() { @@ -441,7 +441,7 @@ someAsyncThing() // carry on ``` -上面代码运行完`catch`方法指定的回调函数,会接着运行后面那个`then`方法指定的回调函数。如果没有报错,则会跳过`catch`方法。 +上面代码运行完`catch`方法指定的回调函数,会接着运行后面那个`then`方法指定的回调函数。**如果没有报错,则会跳过`catch`方法。** ```javascript Promise.resolve() @@ -498,7 +498,7 @@ someAsyncThing().then(function() { ## Promise.prototype.finally() -`finally`方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。 +**`finally`方法用于指定不管 Promise 对象最后状态如何,都会执行的操作**。该方法是 ES2018 引入标准的。 ```javascript promise @@ -519,7 +519,7 @@ server.listen(port) .finally(server.stop); ``` -`finally`方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是`fulfilled`还是`rejected`。这表明,`finally`方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。 +**`finally`方法的回调函数不接受任何参数**,这意味着没有办法知道,前面的 Promise 状态到底是`fulfilled`还是`rejected`。这表明,`finally`方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。 `finally`本质上是`then`方法的特例。 @@ -559,7 +559,7 @@ Promise.prototype.finally = function (callback) { 上面代码中,不管前面的 Promise 是`fulfilled`还是`rejected`,都会执行回调函数`callback`。 -从上面的实现还可以看到,`finally`方法总是会返回原来的值。 +从上面的实现还可以看到,**`finally`方法总是会返回原来的值**。 ```javascript // resolve 的值是 undefined @@ -577,13 +577,13 @@ Promise.reject(3).finally(() => {}) ## Promise.all() -`Promise.all()`方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。 +**`Promise.all()`方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。** ```javascript const p = Promise.all([p1, p2, p3]); ``` -上面代码中,`Promise.all()`方法接受一个数组作为参数,`p1`、`p2`、`p3`都是 Promise 实例,如果不是,就会先调用下面讲到的`Promise.resolve`方法,将参数转为 Promise 实例,再进一步处理。另外,`Promise.all()`方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。 +上面代码中,**`Promise.all()`方法接受一个数组作为参数**,`p1`、`p2`、`p3`都是 Promise 实例,如果不是,就会先调用下面讲到的`Promise.resolve`方法,将参数转为 Promise 实例,再进一步处理。另外,`Promise.all()`方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。 `p`的状态由`p1`、`p2`、`p3`决定,分成两种情况。 @@ -672,7 +672,7 @@ Promise.all([p1, p2]) ## Promise.race() -`Promise.race()`方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。 +**`Promise.race()`方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。** ```javascript const p = Promise.race([p1, p2, p3]); @@ -701,7 +701,7 @@ p ## Promise.allSettled() -`Promise.allSettled()`方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是`fulfilled`还是`rejected`,包装实例才会结束。该方法由 [ES2020](https://github.com/tc39/proposal-promise-allSettled) 引入。 +**`Promise.allSettled()`方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是`fulfilled`还是`rejected`,包装实例才会结束**。该方法由 [ES2020](https://github.com/tc39/proposal-promise-allSettled) 引入。 ```javascript const promises = [ @@ -716,7 +716,7 @@ removeLoadingIndicator(); 上面代码对服务器发出三个请求,等到三个请求都结束,不管请求成功还是失败,加载的滚动图标就会消失。 -该方法返回的新的 Promise 实例,一旦结束,状态总是`fulfilled`,不会变成`rejected`。状态变成`fulfilled`后,Promise 的监听函数接收到的参数是一个数组,每个成员对应一个传入`Promise.allSettled()`的 Promise 实例。 +**该方法返回的新的 Promise 实例,一旦结束,状态总是`fulfilled`,不会变成`rejected`。**状态变成`fulfilled`后,Promise 的监听函数接收到的参数是一个数组,每个成员对应一个传入`Promise.allSettled()`的 Promise 实例。 ```javascript const resolved = Promise.resolve(42); @@ -750,7 +750,7 @@ const errors = results .map(p => p.reason); ``` -有时候,我们不关心异步操作的结果,只关心这些操作有没有结束。这时,`Promise.allSettled()`方法就很有用。如果没有这个方法,想要确保所有操作都结束,就很麻烦。`Promise.all()`方法无法做到这一点。 +**有时候,我们不关心异步操作的结果,只关心这些操作有没有结束。这时,`Promise.allSettled()`方法就很有用。如果没有这个方法,想要确保所有操作都结束,就很麻烦。`Promise.all()`方法无法做到这一点。** ```javascript const urls = [ /* ... */ ]; @@ -768,7 +768,7 @@ try { ## Promise.any() -`Promise.any()`方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成`fulfilled`状态,包装实例就会变成`fulfilled`状态;如果所有参数实例都变成`rejected`状态,包装实例就会变成`rejected`状态。该方法目前是一个第三阶段的[提案](https://github.com/tc39/proposal-promise-any) 。 +**`Promise.any()`方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成`fulfilled`状态,包装实例就会变成`fulfilled`状态;如果所有参数实例都变成`rejected`状态,包装实例就会变成`rejected`状态。**该方法目前是一个第三阶段的[提案](https://github.com/tc39/proposal-promise-any) 。 `Promise.any()`跟`Promise.race()`方法很像,只有一点不同,就是不会因为某个 Promise 变成`rejected`状态而结束。 @@ -830,7 +830,7 @@ Promise.any([rejected, alsoRejected]).catch(function (results) { ## Promise.resolve() -有时需要将现有对象转为 Promise 对象,`Promise.resolve()`方法就起到这个作用。 +**有时需要将现有对象转为 Promise 对象,`Promise.resolve()`方法就起到这个作用。** ```javascript const jsPromise = Promise.resolve($.ajax('/whatever.json')); @@ -850,7 +850,7 @@ new Promise(resolve => resolve('foo')) **(1)参数是一个 Promise 实例** -如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、原封不动地返回这个实例。 +如果参数是 Promise 实例,那么`Promise.resolve`将不做任何修改、**原封不动地返回这个实例**。 **(2)参数是一个`thenable`对象** diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/17.Iterator \345\222\214 for-of \345\276\252\347\216\257.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/17.Iterator \345\222\214 for-of \345\276\252\347\216\257.md" index c5b3488bb0..25f44e7606 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/17.Iterator \345\222\214 for-of \345\276\252\347\216\257.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/17.Iterator \345\222\214 for-of \345\276\252\347\216\257.md" @@ -14,7 +14,7 @@ tags: JavaScript 原有的表示“集合”的数据结构,主要是数组(`Array`)和对象(`Object`),ES6 又添加了`Map`和`Set`。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是`Map`,`Map`的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。 -遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。 +遍历器(Iterator)就是这样一种机制。**它是一种接口,为各种不同的数据结构提供统一的访问机制**。**任何数据结构只要部署 Iterator 接口,就可以完成遍历操作**(即依次处理该数据结构的所有成员)。 Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令`for...of`循环,Iterator 接口主要供`for...of`消费。 @@ -116,11 +116,11 @@ interface IterationResult { ## 默认 Iterator 接口 -Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即`for...of`循环(详见下文)。当使用`for...of`循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。 +I**terator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即`for...of`循环(详见下文)**。当使用`for...of`循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。 -一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。 +**一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”**(iterable)。 -ES6 规定,默认的 Iterator 接口部署在数据结构的`Symbol.iterator`属性,或者说,一个数据结构只要具有`Symbol.iterator`属性,就可以认为是“可遍历的”(iterable)。`Symbol.iterator`属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名`Symbol.iterator`,它是一个表达式,返回`Symbol`对象的`iterator`属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内(参见《Symbol》一章)。 +ES6 规定,**默认的 Iterator 接口部署在数据结构的`Symbol.iterator`属性**,或者说,一个数据结构只要具有`Symbol.iterator`属性,就可以认为是“可遍历的”(iterable)。`Symbol.iterator`属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名`Symbol.iterator`,它是一个表达式,返回`Symbol`对象的`iterator`属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内(参见《Symbol》一章)。 ```javascript const obj = { @@ -141,7 +141,7 @@ const obj = { ES6 的有些数据结构原生具备 Iterator 接口(比如数组),即不用任何处理,就可以被`for...of`循环遍历。原因在于,这些数据结构原生部署了`Symbol.iterator`属性(详见下文),另外一些数据结构没有(比如对象)。凡是部署了`Symbol.iterator`属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。 -原生具备 Iterator 接口的数据结构如下。 +**原生具备 Iterator 接口的数据结构如下。** - Array - Map @@ -276,7 +276,7 @@ NodeList.prototype[Symbol.iterator] = [][Symbol.iterator]; NodeList 对象是类似数组的对象,本来就具有遍历接口,可以直接遍历。上面代码中,我们将它的遍历接口改成数组的`Symbol.iterator`属性,可以看到没有任何影响。 -下面是另一个类似数组的对象调用数组的`Symbol.iterator`方法的例子。 +下面是另一个**类似数组的对象调用数组的`Symbol.iterator`方法的例子**。 ```javascript let iterable = { @@ -291,7 +291,7 @@ for (let item of iterable) { } ``` -注意,普通对象部署数组的`Symbol.iterator`方法,并无效果。 +注意,**普通对象部署数组的`Symbol.iterator`方法,并无效果**。 ```javascript let iterable = { @@ -367,7 +367,7 @@ let arr = ['b', 'c']; 上面代码的扩展运算符内部就调用 Iterator 接口。 -实际上,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,转为数组。也就是说,只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组。 +实际上,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,转为数组。也就是说,**只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组**。 ```javascript let arr = [...iterable]; @@ -406,7 +406,7 @@ iterator.next() // { value: undefined, done: true } ## 字符串的 Iterator 接口 -字符串是一个类似数组的对象,也原生具有 Iterator 接口。 +**字符串是一个类似数组的对象,也原生具有 Iterator 接口**。 ```javascript var someString = "hi"; @@ -529,11 +529,11 @@ for (let line of readLinesSync(fileName)) { ## for...of 循环 -ES6 借鉴 C++、Java、C# 和 Python 语言,引入了`for...of`循环,作为遍历所有数据结构的统一的方法。 +ES6 借鉴 C++、Java、C# 和 Python 语言,引入了`for...of`循环,**作为遍历所有数据结构的统一的方法**。 -一个数据结构只要部署了`Symbol.iterator`属性,就被视为具有 iterator 接口,就可以用`for...of`循环遍历它的成员。也就是说,`for...of`循环内部调用的是数据结构的`Symbol.iterator`方法。 +一个数据结构只要部署了`Symbol.iterator`属性,就被视为具有 iterator 接口,就可以用`for...of`循环遍历它的成员。也就是说,**`for...of`循环内部调用的是数据结构的`Symbol.iterator`方法**。 -`for...of`循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如`arguments`对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。 +`for...of`循环可以使用的范围包括**数组、Set 和 Map 结构、某些类似数组的对象(比如`arguments`对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。** ### 数组 @@ -567,7 +567,7 @@ arr.forEach(function (element, index) { }); ``` -JavaScript 原有的`for...in`循环,只能获得对象的键名,不能直接获取键值。ES6 提供`for...of`循环,允许遍历获得键值。 +JavaScript 原有的**`for...in`循环,只能获得对象的键名**,不能直接获取键值。ES6 提供`for...of`循环,允许遍历获得键值。 ```javascript var arr = ['a', 'b', 'c', 'd']; @@ -581,7 +581,7 @@ for (let a of arr) { } ``` -上面代码表明,`for...in`循环读取键名,`for...of`循环读取键值。如果要通过`for...of`循环,获取数组的索引,可以借助数组实例的`entries`方法和`keys`方法(参见《数组的扩展》一章)。 +上面代码表明,**`for...in`循环读取键名,`for...of`循环读取键值**。如果要通过`for...of`循环,获取数组的索引,可以借助数组实例的`entries`方法和`keys`方法(参见《数组的扩展》一章)。 `for...of`循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟`for...in`循环也不一样。 diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/18.Generator \345\207\275\346\225\260\347\232\204\350\257\255\346\263\225.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/18.Generator \345\207\275\346\225\260\347\232\204\350\257\255\346\263\225.md" index 0fceb465b9..46641c99bb 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/18.Generator \345\207\275\346\225\260\347\232\204\350\257\255\346\263\225.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/18.Generator \345\207\275\346\225\260\347\232\204\350\257\255\346\263\225.md" @@ -14,13 +14,13 @@ tags: ### 基本概念 -Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍 Generator 函数的语法和 API,它的异步编程应用请看《Generator 函数的异步应用》一章。 +Generator 函数是 ES6 提供的一种**异步编程解决方案**,语法行为与传统函数完全不同。本章详细介绍 Generator 函数的语法和 API,它的异步编程应用请看《Generator 函数的异步应用》一章。 -Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。 +Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,**封装了多个内部状态**。 -执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。 +执行 Generator 函数会**返回一个遍历器对象**,也就是说,Generator 函数除了状态机,**还是一个遍历器对象生成函数**。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。 -形式上,Generator 函数是一个普通函数,但是有两个特征。一是,`function`关键字与函数名之间有一个星号;二是,函数体内部使用`yield`表达式,定义不同的内部状态(`yield`在英语里的意思就是“产出”)。 +形式上,Generator 函数是一个普通函数,但是有**两个特征**。一是,**`function`关键字与函数名之间有一个星号**;二是,函数体**内部使用`yield`表达式**,定义不同的内部状态(`yield`在英语里的意思就是“产出”)。 ```javascript function* helloWorldGenerator() { @@ -34,7 +34,7 @@ var hw = helloWorldGenerator(); 上面代码定义了一个 Generator 函数`helloWorldGenerator`,它内部有两个`yield`表达式(`hello`和`world`),即该函数有三个状态:hello,world 和 return 语句(结束执行)。 -然后,Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)。 +然后,Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,**调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象**(Iterator Object)。 下一步,必须调用遍历器对象的`next`方法,使得指针移向下一个状态。也就是说,每次调用`next`方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个`yield`表达式(或`return`语句)为止。换言之,Generator 函数是分段执行的,`yield`表达式是暂停执行的标记,而`next`方法可以恢复执行。 @@ -62,7 +62,7 @@ hw.next() 第四次调用,此时 Generator 函数已经运行完毕,`next`方法返回对象的`value`属性为`undefined`,`done`属性为`true`。以后再调用`next`方法,返回的都是这个值。 -总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的`next`方法,就会返回一个有着`value`和`done`两个属性的对象。`value`属性表示当前的内部状态的值,是`yield`表达式后面那个表达式的值;`done`属性是一个布尔值,表示是否遍历结束。 +**总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的`next`方法,就会返回一个有着`value`和`done`两个属性的对象。`value`属性表示当前的内部状态的值,是`yield`表达式后面那个表达式的值;`done`属性是一个布尔值,表示是否遍历结束。** ES6 没有规定,`function`关键字与函数名之间的星号,写在哪个位置。这导致下面的写法都能通过。 @@ -89,7 +89,7 @@ function*foo(x, y) { ··· } (4)如果该函数没有`return`语句,则返回的对象的`value`属性值为`undefined`。 -需要注意的是,`yield`表达式后面的表达式,只有当调用`next`方法、内部指针指向该语句时才会执行,因此等于为 JavaScript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。 +需要注意的是,**`yield`表达式后面的表达式,只有当调用`next`方法、内部指针指向该语句时才会执行**,因此等于为 JavaScript 提供了手动的“**惰性求值**”(Lazy Evaluation)的语法功能。 ```javascript function* gen() { @@ -99,7 +99,7 @@ function* gen() { 上面代码中,`yield`后面的表达式`123 + 456`,不会立即求值,只会在`next`方法将指针移到这一句时,才会求值。 -`yield`表达式与`return`语句既有相似之处,也有区别。相似之处在于,都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到`yield`,函数暂停执行,下一次再从该位置继续向后执行,而`return`语句不具备位置记忆的功能。一个函数里面,只能执行一次(或者说一个)`return`语句,但是可以执行多次(或者说多个)`yield`表达式。正常函数只能返回一个值,因为只能执行一次`return`;Generator 函数可以返回一系列的值,因为可以有任意多个`yield`。从另一个角度看,也可以说 Generator 生成了一系列的值,这也就是它的名称的来历(英语中,generator 这个词是“生成器”的意思)。 +`yield`表达式与`return`语句既有相似之处,也有区别。相似之处在于,都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到`yield`,函数暂停执行,下一次再从该位置继续向后执行,而**`return`语句不具备位置记忆的功能**。一个函数里面,只能执行一次(或者说一个)`return`语句,但是可以执行多次(或者说多个)`yield`表达式。正常函数只能返回一个值,因为只能执行一次`return`;**Generator 函数可以返回一系列的值,因为可以有任意多个`yield`**。从另一个角度看,也可以说 Generator 生成了一系列的值,这也就是它的名称的来历(英语中,generator 这个词是“生成器”的意思)。 Generator 函数可以不用`yield`表达式,这时就变成了一个单纯的暂缓执行函数。 @@ -148,7 +148,7 @@ for (var f of flat(arr)){ } ``` -上面代码也会产生句法错误,因为`forEach`方法的参数是一个普通函数,但是在里面使用了`yield`表达式(这个函数里面还使用了`yield*`表达式,详细介绍见后文)。一种修改方法是改用`for`循环。 +上面代码也会**产生句法错误,因为`forEach`方法的参数是一个普通函数**,但是在里面使用了`yield`表达式(这个函数里面还使用了`yield*`表达式,详细介绍见后文)。一种修改方法是改用`for`循环。 ```javascript var arr = [1, [[2, 3], 4], [5, 6]]; @@ -171,7 +171,7 @@ for (var f of flat(arr)) { // 1, 2, 3, 4, 5, 6 ``` -另外,`yield`表达式如果用在另一个表达式之中,必须放在圆括号里面。 +另外,**`yield`表达式如果用在另一个表达式之中,必须放在圆括号里面。** ```javascript function* demo() { @@ -196,7 +196,7 @@ function* demo() { 上一章说过,任意一个对象的`Symbol.iterator`方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。 -由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的`Symbol.iterator`属性,从而使得该对象具有 Iterator 接口。 +由于 Generator 函数就是遍历器生成函数,因此**可以把 Generator 赋值给对象的`Symbol.iterator`属性,从而使得该对象具有 Iterator 接口。** ```javascript var myIterable = {}; @@ -242,12 +242,12 @@ var g = f(); g.next() // { value: 0, done: false } g.next() // { value: 1, done: false } -g.next(true) // { value: 0, done: false } +g.next(true) // { value: 0, done: false } // 参数true 传给上面的变量reset ``` 上面代码先定义了一个可以无限运行的 Generator 函数`f`,如果`next`方法没有参数,每次运行到`yield`表达式,变量`reset`的值总是`undefined`。当`next`方法带一个参数`true`时,变量`reset`就被重置为这个参数(即`true`),因此`i`会等于`-1`,下一轮循环就会从`-1`开始递增。 -这个功能有很重要的语法意义。Generator 函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过`next`方法的参数,就有办法在 Generator 函数开始运行之后,继续向函数体内部注入值。也就是说,可以在 Generator 函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数行为。 +这个功能有很重要的语法意义。Generator 函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过`next`方法的参数,就有办法在 Generator 函数开始运行之后,继续向函数体内部注入值。也就是说,可以在 Generator 函数运行的不同阶段,**从外部向内部注入不同的值,从而调整函数行为**。 再看一个例子。 @@ -273,7 +273,7 @@ b.next(13) // { value:42, done:true } 如果向`next`方法提供参数,返回结果就完全不一样了。上面代码第一次调用`b`的`next`方法时,返回`x+1`的值`6`;第二次调用`next`方法,将上一次`yield`表达式的值设为`12`,因此`y`等于`24`,返回`y / 3`的值`8`;第三次调用`next`方法,将上一次`yield`表达式的值设为`13`,因此`z`等于`13`,这时`x`等于`5`,`y`等于`24`,所以`return`语句的值等于`42`。 -注意,由于`next`方法的参数表示上一个`yield`表达式的返回值,所以在第一次使用`next`方法时,传递参数是无效的。V8 引擎直接忽略第一次使用`next`方法时的参数,只有从第二次使用`next`方法开始,参数才是有效的。从语义上讲,第一个`next`方法用来启动遍历器对象,所以不用带有参数。 +注意,**由于`next`方法的参数表示上一个`yield`表达式的返回值,所以在第一次使用`next`方法时,传递参数是无效的**。V8 引擎直接忽略第一次使用`next`方法时的参数,只有从第二次使用`next`方法开始,参数才是有效的。从语义上讲,第一个`next`方法用来启动遍历器对象,所以不用带有参数。 再看一个通过`next`方法的参数,向 Generator 函数内部输入值的例子。 @@ -677,7 +677,7 @@ log(g()); ## Generator.prototype.return() -Generator 函数返回的遍历器对象,还有一个`return`方法,可以返回给定的值,并且终结遍历 Generator 函数。 +Generator 函数返回的遍历器对象,还有一个**`return`方法,可以返回给定的值,并且终结遍历 Generator 函数。** ```javascript function* gen() { diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/19.Generator \345\207\275\346\225\260\347\232\204\345\274\202\346\255\245\345\272\224\347\224\250.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/19.Generator \345\207\275\346\225\260\347\232\204\345\274\202\346\255\245\345\272\224\347\224\250.md" index 7f6bfd6571..6999fd6eea 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/19.Generator \345\207\275\346\225\260\347\232\204\345\274\202\346\255\245\345\272\224\347\224\250.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/19.Generator \345\207\275\346\225\260\347\232\204\345\274\202\346\255\245\345\272\224\347\224\250.md" @@ -12,6 +12,7 @@ tags: 异步编程对 JavaScript 语言太重要。JavaScript 语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。本章主要介绍 Generator 函数如何完成异步操作。 + ## 传统方法 ES6 诞生以前,异步编程的方法,大概有下面四种。 @@ -98,7 +99,7 @@ Promise 的最大问题是代码冗余,原来的任务被 Promise 包装了一 ### 协程 -传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案)。其中有一种叫做"协程"(coroutine),意思是多个线程互相协作,完成异步任务。 +传统的编程语言,早有异步编程的解决方案(其实是多任务的解决方案)。其中有一种叫做"协程"(coroutine),意思是**多个线程互相协作,完成异步任务**。 协程有点像函数,又有点像线程。它的运行流程大致如下。 @@ -140,15 +141,15 @@ g.next() // { value: 3, done: false } g.next() // { value: undefined, done: true } ``` -上面代码中,调用 Generator 函数,会返回一个内部指针(即遍历器)`g`。这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。调用指针`g`的`next`方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的`yield`语句,上例是执行到`x + 2`为止。 +上面代码中,调用 Generator 函数,会返回一个内部指针(即遍历器)`g`。这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,**返回的是指针对象。调用指针`g`的`next`方法,会移动内部指针**(即执行异步任务的第一段),指向第一个遇到的`yield`语句,上例是执行到`x + 2`为止。 -换言之,`next`方法的作用是分阶段执行`Generator`函数。每次调用`next`方法,会返回一个对象,表示当前阶段的信息(`value`属性和`done`属性)。`value`属性是`yield`语句后面表达式的值,表示当前阶段的值;`done`属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。 +换言之,**`next`方法的作用是分阶段执行`Generator`函数**。每次调用`next`方法,会返回一个对象,表示当前阶段的信息(`value`属性和`done`属性)。**`value`属性是`yield`语句后面表达式的值,表示当前阶段的值**;`done`属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。 ### Generator 函数的数据交换和错误处理 -Generator 函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。 +**Generator 函数可以暂停执行和恢复执行**,这是它能封装异步任务的根本原因。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:**函数体内外的数据交换和错误处理机制**。 -`next`返回值的 value 属性,是 Generator 函数向外输出数据;`next`方法还可以接受参数,向 Generator 函数体内输入数据。 +**`next`返回值的 value 属性,是 Generator 函数向外输出数据;`next`方法还可以接受参数,向 Generator 函数体内输入数据。** ```javascript function* gen(x){ @@ -163,7 +164,7 @@ g.next(2) // { value: 2, done: true } 上面代码中,第一个`next`方法的`value`属性,返回表达式`x + 2`的值`3`。第二个`next`方法带有参数`2`,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量`y`接收。因此,这一步的`value`属性,返回的就是`2`(变量`y`的值)。 -Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。 +**Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误**。 ```javascript function* gen(x){ @@ -181,7 +182,7 @@ g.throw('出错了'); // 出错了 ``` -上面代码的最后一行,Generator 函数体外,使用指针对象的`throw`方法抛出的错误,可以被函数体内的`try...catch`代码块捕获。这意味着,出错的代码与处理错误的代码,实现了时间和空间上的分离,这对于异步编程无疑是很重要的。 +上面代码的最后一行,Generator 函数体外,使用指针对象的`throw`方法抛出的错误,可以被函数体内的`try...catch`代码块捕获。这意味着,**出错的代码与处理错误的代码,实现了时间和空间上的分离**,这对于异步编程无疑是很重要的。 ### 异步任务的封装 @@ -214,7 +215,7 @@ result.value.then(function(data){ 上面代码中,首先执行 Generator 函数,获取遍历器对象,然后使用`next`方法(第二行),执行异步任务的第一阶段。由于`Fetch`模块返回的是一个 Promise 对象,因此要用`then`方法调用下一个`next`方法。 -可以看到,虽然 Generator 函数将异步操作表示得很简洁,但是流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。 +可以看到,**虽然 Generator 函数将异步操作表示得很简洁,但是流程管理却不方便**(即何时执行第一阶段、何时执行第二阶段)。 ## Thunk 函数 @@ -292,7 +293,7 @@ function f(thunk) { 上面代码中,函数 f 的参数`x + 5`被一个函数替换了。凡是用到原参数的地方,对`Thunk`函数求值即可。 -这就是 Thunk 函数的定义,它是“传名调用”的一种实现策略,用来替换某个表达式。 +这就是 Thunk 函数的定义,**它是“传名调用”的一种实现策略,用来替换某个表达式。** ### JavaScript 语言的 Thunk 函数 @@ -315,7 +316,7 @@ readFileThunk(callback); 上面代码中,`fs`模块的`readFile`方法是一个多参数函数,两个参数分别为文件名和回调函数。经过转换器处理,它变成了一个单参数函数,只接受回调函数作为参数。这个单参数版本,就叫做 Thunk 函数。 -任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式。下面是一个简单的 Thunk 函数转换器。 +**任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式**。下面是一个简单的 Thunk 函数转换器。 ```javascript // ES5版本 @@ -429,7 +430,7 @@ ft(1, 2)(print); ### Generator 函数的流程管理 -你可能会问, Thunk 函数有什么用?回答是以前确实没什么用,但是 ES6 有了 Generator 函数,Thunk 函数现在可以用于 Generator 函数的自动流程管理。 +你可能会问, Thunk 函数有什么用?回答是以前确实没什么用,但是 ES6 有了 Generator 函数,**Thunk 函数现在可以用于 Generator 函数的自动流程管理**。 Generator 函数可以自动执行。 diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/20.async \345\207\275\346\225\260.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/20.async \345\207\275\346\225\260.md" index 81c72b5265..939de2feca 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/20.async \345\207\275\346\225\260.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/20.async \345\207\275\346\225\260.md" @@ -14,10 +14,11 @@ tags: ES2017 标准引入了 async 函数,使得异步操作变得更加方便。 -async 函数是什么?一句话,它就是 Generator 函数的语法糖。 +async 函数是什么?一句话,它就**是 Generator 函数的语法糖**。 前文有一个 Generator 函数,依次读取两个文件。 + ```javascript const fs = require('fs'); @@ -49,7 +50,7 @@ const asyncReadFile = async function () { }; ``` -一比较就会发现,`async`函数就是将 Generator 函数的星号(`*`)替换成`async`,将`yield`替换成`await`,仅此而已。 +一比较就会发现,**`async`函数就是将 Generator 函数的星号(`*`)替换成`async`,将`yield`替换成`await`,仅此而已。** `async`函数对 Generator 函数的改进,体现在以下四点。 @@ -75,11 +76,11 @@ asyncReadFile(); `async`函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用`then`方法指定下一步的操作。 -进一步说,`async`函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而`await`命令就是内部`then`命令的语法糖。 +进一步说,**`async`函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而`await`命令就是内部`then`命令的语法糖。** ## 基本用法 -`async`函数返回一个 Promise 对象,可以使用`then`方法添加回调函数。当函数执行的时候,一旦遇到`await`就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。 +**`async`函数返回一个 Promise 对象**,可以使用`then`方法添加回调函数。当函数执行的时候,一旦遇到`await`就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。 下面是一个例子。 @@ -167,13 +168,13 @@ const foo = async () => {}; ## 语法 -`async`函数的语法规则总体上比较简单,难点是错误处理机制。 +`async`函数的语法规则总体上比较简单,**难点是错误处理机制。** ### 返回 Promise 对象 `async`函数返回一个 Promise 对象。 -`async`函数内部`return`语句返回的值,会成为`then`方法回调函数的参数。 +**`async`函数内部`return`语句返回的值,会成为`then`方法回调函数的参数**。 ```javascript async function f() { @@ -186,7 +187,7 @@ f().then(v => console.log(v)) 上面代码中,函数`f`内部`return`命令返回的值,会被`then`方法回调函数接收到。 -`async`函数内部抛出错误,会导致返回的 Promise 对象变为`reject`状态。抛出的错误对象会被`catch`方法回调函数接收到。 +**`async`函数内部抛出错误,会导致返回的 Promise 对象变为`reject`状态**。抛出的错误对象会被`catch`方法回调函数接收到。 ```javascript async function f() { @@ -202,7 +203,7 @@ f().then( ### Promise 对象的状态变化 -`async`函数返回的 Promise 对象,必须等到内部所有`await`命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到`return`语句或者抛出错误。也就是说,只有`async`函数内部的异步操作执行完,才会执行`then`方法指定的回调函数。 +`async`函数返回的 Promise 对象,必须等到内部所有`await`命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到`return`语句或者抛出错误。也就是说,**只有`async`函数内部的异步操作执行完,才会执行`then`方法指定的回调函数。** 下面是一个例子。 @@ -387,7 +388,7 @@ async function main() { } ``` -下面的例子使用`try...catch`结构,实现多次重复尝试。 +下面的例子使用`try...catch`结构,**实现多次重复尝试**。 ```javascript const superagent = require('superagent'); @@ -411,7 +412,7 @@ test(); ### 使用注意点 -第一点,前面已经说过,`await`命令后面的`Promise`对象,运行结果可能是`rejected`,所以最好把`await`命令放在`try...catch`代码块中。 +第一点,前面已经说过,`await`命令后面的`Promise`对象,运行结果可能是`rejected`,所以**最好把`await`命令放在`try...catch`代码块中**。 ```javascript async function myFunction() { @@ -432,7 +433,7 @@ async function myFunction() { } ``` -第二点,多个`await`命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。 +第二点,多个`await`命令后面的异步操作,**如果不存在继发关系,最好让它们同时触发(并发)**。 ```javascript let foo = await getFoo(); @@ -540,7 +541,7 @@ const a = async () => { ## async 函数的实现原理 -async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。 +async 函数的实现原理**,就是将 Generator 函数和自动执行器,包装在一个函数里**。 ```javascript async function fn(args) { @@ -713,7 +714,7 @@ async function logInOrder(urls) { } ``` -上面代码中,虽然`map`方法的参数是`async`函数,但它是并发执行的,因为只有`async`函数内部是继发执行,外部不受影响。后面的`for..of`循环内部使用了`await`,因此实现了按顺序输出。 +上面代码中,**虽然`map`方法的参数是`async`函数,但它是并发执行的**,因为只有`async`函数内部是继发执行,外部不受影响。后面的`for..of`循环内部使用了`await`,因此实现了按顺序输出。 ## 顶层 await @@ -802,7 +803,7 @@ promise.then(() => { 这种写法比较麻烦,等于要求模块的使用者遵守一个额外的使用协议,按照特殊的方法使用这个模块。一旦你忘了要用 Promise 加载,只使用正常的加载方法,依赖这个模块的代码就可能出错。而且,如果上面的`usage.js`又有对外的输出,等于这个依赖链的所有模块都要使用 Promise 加载。 -顶层的`await`命令,就是为了解决这个问题。它保证只有异步操作完成,模块才会输出值。 +**顶层的`await`命令,就是为了解决这个问题。它保证只有异步操作完成,模块才会输出值**。 ```javascript // awaiting.js diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/21.Class \347\232\204\345\237\272\346\234\254\350\257\255\346\263\225.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/21.Class \347\232\204\345\237\272\346\234\254\350\257\255\346\263\225.md" index fb93d21a68..562b19e2cd 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/21.Class \347\232\204\345\237\272\346\234\254\350\257\255\346\263\225.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/21.Class \347\232\204\345\237\272\346\234\254\350\257\255\346\263\225.md" @@ -50,7 +50,7 @@ class Point { 上面代码定义了一个“类”,可以看到里面有一个`constructor`方法,这就是构造方法,而`this`关键字则代表实例对象。也就是说,ES5 的构造函数`Point`,对应 ES6 的`Point`类的构造方法。 -`Point`类除了构造方法,还定义了一个`toString`方法。注意,定义“类”的方法的时候,前面不需要加上`function`这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。 +`Point`类除了构造方法,还定义了一个`toString`方法。注意,**定义“类”的方法的时候,前面不需要加上`function`这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。** ES6 的类,完全可以看作构造函数的另一种写法。 @@ -78,7 +78,7 @@ var b = new Bar(); b.doStuff() // "stuff" ``` -构造函数的`prototype`属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的`prototype`属性上面。 +构造函数的`prototype`属性,在 ES6 的“类”上面继续存在。事实上,**类的所有方法都定义在类的`prototype`属性上面。** ```javascript class Point { @@ -115,7 +115,7 @@ b.constructor === B.prototype.constructor // true 上面代码中,`b`是`B`类的实例,它的`constructor`方法就是`B`类原型的`constructor`方法。 -由于类的方法都定义在`prototype`对象上面,所以类的新方法可以添加在`prototype`对象上面。`Object.assign`方法可以很方便地一次向类添加多个方法。 +由于类的方法都定义在`prototype`对象上面,所以类的新方法可以添加在`prototype`对象上面。**`Object.assign`方法可以很方便地一次向类添加多个方法。** ```javascript class Point { @@ -136,7 +136,7 @@ Object.assign(Point.prototype, { Point.prototype.constructor === Point // true ``` -另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。 +另外,**类的内部所有定义的方法,都是不可枚举的**(non-enumerable)。 ```javascript class Point { @@ -176,7 +176,7 @@ Object.getOwnPropertyNames(Point.prototype) ### constructor 方法 -`constructor`方法是类的默认方法,通过`new`命令生成对象实例时,自动调用该方法。一个类必须有`constructor`方法,如果没有显式定义,一个空的`constructor`方法会被默认添加。 +`constructor`方法是类的默认方法,**通过`new`命令生成对象实例时,自动调用该方法**。一个类必须有`constructor`方法,如果没有显式定义,一个空的`constructor`方法会被默认添加。 ```javascript class Point { @@ -205,7 +205,7 @@ new Foo() instanceof Foo 上面代码中,`constructor`函数返回一个全新的对象,结果导致实例对象不是`Foo`类的实例。 -类必须使用`new`调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用`new`也可以执行。 +**类必须使用`new`调用,否则会报错**。这是它跟普通构造函数的一个主要区别,后者不用`new`也可以执行。 ```javascript class Foo { @@ -240,12 +240,12 @@ var point = new Point(2, 3); //定义类 class Point { - constructor(x, y) { - this.x = x; - this.y = y; + constructor(x, y) { // constructor属性定义在原型上 + this.x = x; // x属性定义在实例上 + this.y = y; // y属性定义在实例上 } - toString() { + toString() { // toString属性定义在原型上 return '(' + this.x + ', ' + this.y + ')'; } @@ -322,7 +322,7 @@ inst.prop 上面代码中,`prop`属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了。 -存值函数和取值函数是设置在属性的 Descriptor 对象上的。 +**存值函数和取值函数是设置在属性的 Descriptor 对象上的。** ```javascript class CustomHTMLElement { @@ -553,7 +553,7 @@ const logger = selfish(new Logger()); ## 静态方法 -类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上`static`关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。 +类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,**加上`static`关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”**。 ```javascript class Foo { @@ -571,7 +571,7 @@ foo.classMethod() 上面代码中,`Foo`类的`classMethod`方法前有`static`关键字,表明该方法是一个静态方法,可以直接在`Foo`类上调用(`Foo.classMethod()`),而不是在`Foo`类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。 -注意,如果静态方法包含`this`关键字,这个`this`指的是类,而不是实例。 +注意,**如果静态方法包含`this`关键字,这个`this`指的是类,而不是实例。** ```javascript class Foo { diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/22.Class \347\232\204\347\273\247\346\211\277.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/22.Class \347\232\204\347\273\247\346\211\277.md" index 14aa578ecd..5f1c7e9a98 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/22.Class \347\232\204\347\273\247\346\211\277.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/22.Class \347\232\204\347\273\247\346\211\277.md" @@ -39,7 +39,7 @@ class ColorPoint extends Point { 上面代码中,`constructor`方法和`toString`方法之中,都出现了`super`关键字,它在这里表示父类的构造函数,用来新建父类的`this`对象。 -子类必须在`constructor`方法中调用`super`方法,否则新建实例时会报错。这是因为子类自己的`this`对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用`super`方法,子类就得不到`this`对象。 +**子类必须在`constructor`方法中调用`super`方法,否则新建实例时会报错。**这是因为子类自己的`this`对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。**如果不调用`super`方法,子类就得不到`this`对象。** ```javascript class Point { /* ... */ } @@ -70,7 +70,7 @@ class ColorPoint extends Point { } ``` -另一个需要注意的地方是,在子类的构造函数中,只有调用`super`之后,才可以使用`this`关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有`super`方法才能调用父类实例。 +另一个需要注意的地方是,**在子类的构造函数中,只有调用`super`之后,才可以使用`this`关键字,否则会报错。**这是因为子类实例的构建,基于父类实例,只有`super`方法才能调用父类实例。 ```javascript class Point { @@ -132,7 +132,7 @@ Object.getPrototypeOf(ColorPoint) === Point ## super 关键字 -`super`这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。 +**`super`这个关键字,既可以当作函数使用,也可以当作对象使用**。在这两种情况下,它的用法完全不同。 第一种情况,`super`作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次`super`函数。 @@ -148,7 +148,7 @@ class B extends A { 上面代码中,子类`B`的构造函数之中的`super()`,代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。 -注意,`super`虽然代表了父类`A`的构造函数,但是返回的是子类`B`的实例,即`super`内部的`this`指的是`B`的实例,因此`super()`在这里相当于`A.prototype.constructor.call(this)`。 +注意,**`super`虽然代表了父类`A`的构造函数,但是返回的是子类`B`的实例**,即`super`内部的`this`指的是`B`的实例,因此`super()`在这里相当于`A.prototype.constructor.call(this)`。 ```javascript class A { @@ -167,7 +167,7 @@ new B() // B 上面代码中,`new.target`指向当前正在执行的函数。可以看到,在`super()`执行时,它指向的是子类`B`的构造函数,而不是父类`A`的构造函数。也就是说,`super()`内部的`this`指向的是`B`。 -作为函数时,`super()`只能用在子类的构造函数之中,用在其他地方就会报错。 +**作为函数时,`super()`只能用在子类的构造函数之中,用在其他地方就会报错。** ```javascript class A {} @@ -181,7 +181,7 @@ class B extends A { 上面代码中,`super()`用在`B`类的`m`方法之中,就会造成语法错误。 -第二种情况,`super`作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。 +第二种情况,**`super`作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。** ```javascript class A { @@ -207,7 +207,7 @@ let b = new B(); ```javascript class A { constructor() { - this.p = 2; + this.p = 2; // 这是定于在实例上的属性 } } @@ -241,7 +241,7 @@ let b = new B(); 上面代码中,属性`x`是定义在`A.prototype`上面的,所以`super.x`可以取到它的值。 -ES6 规定,在子类普通方法中通过`super`调用父类的方法时,方法内部的`this`指向当前的子类实例。 +ES6 规定,**在子类普通方法中通过`super`调用父类的方法时,方法内部的`this`指向当前的子类实例**。 ```javascript class A { @@ -274,7 +274,7 @@ b.m() // 2 ```javascript class A { constructor() { - this.x = 1; + this.x = 1; } } @@ -293,7 +293,7 @@ let b = new B(); 上面代码中,`super.x`赋值为`3`,这时等同于对`this.x`赋值为`3`。而当读取`super.x`的时候,读的是`A.prototype.x`,所以返回`undefined`。 -如果`super`作为对象,用在静态方法之中,这时`super`将指向父类,而不是父类的原型对象。 +**如果`super`作为对象,用在静态方法之中,这时`super`将指向父类,而不是父类的原型对象。** ```javascript class Parent { @@ -324,7 +324,7 @@ child.myMethod(2); // instance 2 上面代码中,`super`在静态方法之中指向父类,在普通方法之中指向父类的原型对象。 -另外,在子类的静态方法中通过`super`调用父类的方法时,方法内部的`this`指向当前的子类,而不是子类的实例。 +另外,**在子类的静态方法中通过`super`调用父类的方法时,方法内部的`this`指向当前的子类,而不是子类的实例。** ```javascript class A { diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/23.Module \347\232\204\350\257\255\346\263\225.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/23.Module \347\232\204\350\257\255\346\263\225.md" index 74494ebcc0..5f05a13fbc 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/23.Module \347\232\204\350\257\255\346\263\225.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/23.Module \347\232\204\350\257\255\346\263\225.md" @@ -29,7 +29,7 @@ let exists = _fs.exists; let readfile = _fs.readfile; ``` -上面代码的实质是整体加载`fs`模块(即加载`fs`的所有方法),生成一个对象(`_fs`),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。 +上面代码的实质是整体加载`fs`模块(即加载`fs`的所有方法),生成一个对象(`_fs`),然后再从这个对象上面读取 3 个方法。**这种加载称为“运行时加载”**,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。 ES6 模块不是对象,而是通过`export`命令显式指定输出的代码,再通过`import`命令输入。 @@ -38,7 +38,7 @@ ES6 模块不是对象,而是通过`export`命令显式指定输出的代码 import { stat, exists, readFile } from 'fs'; ``` -上面代码的实质是从`fs`模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。 +上面代码的实质是从`fs`模块加载 3 个方法,其他方法不加载。**这种加载称为“编译时加载”或者静态加载**,**即 ES6 可以在编译时就完成模块加载,**效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。 由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。 @@ -52,7 +52,7 @@ import { stat, exists, readFile } from 'fs'; ## 严格模式 -ES6 的模块自动采用严格模式,不管你有没有在模块头部加上`"use strict";`。 +**ES6 的模块自动采用严格模式**,不管你有没有在模块头部加上`"use strict";`。 严格模式主要有以下限制。 @@ -80,7 +80,7 @@ ES6 的模块自动采用严格模式,不管你有没有在模块头部加上` 模块功能主要由两个命令构成:`export`和`import`。`export`命令用于规定模块的对外接口,`import`命令用于输入其他模块提供的功能。 -一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用`export`关键字输出该变量。下面是一个 JS 文件,里面使用`export`命令输出变量。 +**一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用`export`关键字输出该变量**。下面是一个 JS 文件,里面使用`export`命令输出变量。 ```javascript // profile.js @@ -114,7 +114,7 @@ export function multiply(x, y) { 上面代码对外输出一个函数`multiply`。 -通常情况下,`export`输出的变量就是本来的名字,但是可以使用`as`关键字重命名。 +通常情况下,`export`输出的变量就是本来的名字,但是**可以使用`as`关键字重命名**。 ```javascript function v1() { ... } @@ -172,7 +172,7 @@ function f() {} export {f}; ``` -另外,`export`语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。 +另外,`export`语句输出的接口,与其对应的**值是动态绑定关系**,即通过该接口,可以取到模块内部实时的值。 ```javascript export var foo = 'bar'; @@ -207,15 +207,15 @@ function setName(element) { } ``` -上面代码的`import`命令,用于加载`profile.js`文件,并从中输入变量。`import`命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(`profile.js`)对外接口的名称相同。 +上面代码的`import`命令,用于加载`profile.js`文件,并从中输入变量。`import`命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的**变量名,必须与被导入模块(`profile.js`)对外接口的名称相同。** -如果想为输入的变量重新取一个名字,`import`命令要使用`as`关键字,将输入的变量重命名。 +如果想为输入的变量重新取一个名字**,`import`命令要使用`as`关键字,将输入的变量重命名。** ```javascript import { lastName as surname } from './profile.js'; ``` -`import`命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。 +**`import`命令输入的变量都是只读的**,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。 ```javascript import {a} from './xxx.js' @@ -223,7 +223,7 @@ import {a} from './xxx.js' a = {}; // Syntax Error : 'a' is read-only; ``` -上面代码中,脚本加载了变量`a`,对其重新赋值就会报错,因为`a`是一个只读的接口。但是,如果`a`是一个对象,改写`a`的属性是允许的。 +上面代码中,脚本加载了变量`a`,对其重新赋值就会报错,因为`a`是一个只读的接口。但是**,如果`a`是一个对象,改写`a`的属性是允许的**。 ```javascript import {a} from './xxx.js' @@ -231,9 +231,9 @@ import {a} from './xxx.js' a.foo = 'hello'; // 合法操作 ``` -上面代码中,`a`的属性可以成功改写,并且其他模块也可以读到改写后的值。不过,这种写法很难查错,建议凡是输入的变量,都当作完全只读,不要轻易改变它的属性。 +上面代码中,`a`的属性可以成功改写,并且其他模块也可以读到改写后的值。不过,这种写法很难查错,**建议凡是输入的变量,都当作完全只读,不要轻易改变它的属性**。 -`import`后面的`from`指定模块文件的位置,可以是相对路径,也可以是绝对路径,`.js`后缀可以省略。如果只是模块名,不带有路径,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。 +`import`后面的`from`指定模块文件的位置,可以是相对路径,也可以是绝对路径,**`.js`后缀可以省略**。**如果只是模块名,不带有路径,那么必须有配置文件**,告诉 JavaScript 引擎该模块的位置。 ```javascript import {myMethod} from 'util'; @@ -241,7 +241,7 @@ import {myMethod} from 'util'; 上面代码中,`util`是模块文件名,由于不带有路径,必须通过配置,告诉引擎怎么取到这个模块。 -注意,`import`命令具有提升效果,会提升到整个模块的头部,首先执行。 +注意,**`import`命令具有提升效果,会提升到整个模块的头部**,首先执行。 ```javascript foo(); @@ -251,7 +251,7 @@ import { foo } from 'my_module'; 上面的代码不会报错,因为`import`的执行早于`foo`的调用。这种行为的本质是,`import`命令是编译阶段执行的,在代码运行之前。 -由于`import`是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。 +由于`import`是静态执行,所以**不能使用表达式和变量**,这些只有在运行时才能得到结果的语法结构。 ```javascript // 报错 @@ -306,7 +306,7 @@ require('core-js/modules/es6.promise'); import React from 'React'; ``` -## 模块的整体加载 +## 模块的整体加载-(星号*) 除了指定加载某个输出值,还可以使用整体加载,即用星号(`*`)指定一个对象,所有输出值都加载在这个对象上面。 @@ -344,7 +344,7 @@ console.log('圆面积:' + circle.area(4)); console.log('圆周长:' + circle.circumference(14)); ``` -注意,模块整体加载所在的那个对象(上例是`circle`),应该是可以静态分析的,所以不允许运行时改变。下面的写法都是不允许的。 +注意,**模块整体加载所在的那个对象(上例是`circle`),应该是可以静态分析的,所以不允许运行时改变**。下面的写法都是不允许的。 ```javascript import * as circle from './circle'; @@ -358,7 +358,7 @@ circle.area = function () {}; 从前面的例子可以看出,使用`import`命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。 -为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到`export default`命令,为模块指定默认输出。 +为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到**`export default`命令,为模块指定默认输出。** ```javascript // export-default.js @@ -369,7 +369,7 @@ export default function () { 上面代码是一个模块文件`export-default.js`,它的默认输出是一个函数。 -其他模块加载该模块时,`import`命令可以为该匿名函数指定任意名字。 +其他模块加载该模块时,**`import`命令可以为该匿名函数指定任意名字。** ```javascript // import-default.js @@ -377,7 +377,7 @@ import customName from './export-default'; customName(); // 'foo' ``` -上面代码的`import`命令,可以用任意名称指向`export-default.js`输出的方法,这时就不需要知道原模块输出的函数名。需要注意的是,这时`import`命令后面,不使用大括号。 +上面代码的`import`命令,可以用任意名称指向`export-default.js`输出的方法,这时就不需要知道原模块输出的函数名。需要注意的是,**这时`import`命令后面,不使用大括号**。 `export default`命令用在非匿名函数前,也是可以的。 @@ -396,7 +396,7 @@ function foo() { export default foo; ``` -上面代码中,`foo`函数的函数名`foo`,在模块外部是无效的。加载的时候,视同匿名函数加载。 +上面代码中,**`foo`函数的函数名`foo`,在模块外部是无效的。加载的时候,视同匿名函数加载**。 下面比较一下默认输出和正常输出。 @@ -418,9 +418,9 @@ import {crc32} from 'crc32'; // 输入 上面代码的两组写法,第一组是使用`export default`时,对应的`import`语句不需要使用大括号;第二组是不使用`export default`时,对应的`import`语句需要使用大括号。 -`export default`命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此`export default`命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应`export default`命令。 +`export default`命令用于指定模块的默认输出。显然,**一个模块只能有一个默认输出**,因此`export default`命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应`export default`命令。 -本质上,`export default`就是输出一个叫做`default`的变量或方法,然后系统允许你为它取任意名字。所以,下面的写法是有效的。 +**本质上,`export default`就是输出一个叫做`default`的变量或方法,**然后系统允许你为它取任意名字。所以,下面的写法是有效的。 ```javascript // modules.js @@ -680,7 +680,7 @@ const myModual = require(path); 上面的语句就是动态加载,`require`到底加载哪一个模块,只有运行时才知道。`import`命令做不到这一点。 -[ES2020提案](https://github.com/tc39/proposal-dynamic-import) 引入`import()`函数,支持动态加载模块。 +**[ES2020提案](https://github.com/tc39/proposal-dynamic-import) 引入`import()`函数,支持动态加载模块。** ```javascript import(specifier) @@ -688,7 +688,7 @@ import(specifier) 上面代码中,`import`函数的参数`specifier`,指定所要加载的模块的位置。`import`命令能够接受什么参数,`import()`函数就能接受什么参数,两者区别主要是后者为动态加载。 -`import()`返回一个 Promise 对象。下面是一个例子。 +**`import()`返回一个 Promise 对象**。下面是一个例子。 ```javascript const main = document.querySelector('main'); @@ -702,7 +702,7 @@ import(`./section-modules/${someVariable}.js`) }); ``` -`import()`函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,`import()`函数与所加载的模块没有静态连接关系,这点也是与`import`语句不相同。`import()`类似于 Node 的`require`方法,区别主要是前者是异步加载,后者是同步加载。 +**`import()`函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用**。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,`import()`函数与所加载的模块没有静态连接关系,这点也是与`import`语句不相同。`import()`类似于 Node 的`require`方法,区别主要是前者是异步加载,后者是同步加载。 ### 适用场合 diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/24.Module \347\232\204\345\212\240\350\275\275\345\256\236\347\216\260.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/24.Module \347\232\204\345\212\240\350\275\275\345\256\236\347\216\260.md" index 4379e278a7..f462366089 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/24.Module \347\232\204\345\212\240\350\275\275\345\256\236\347\216\260.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/24.Module \347\232\204\345\212\240\350\275\275\345\256\236\347\216\260.md" @@ -42,7 +42,7 @@ HTML 网页中,浏览器通过` @@ -93,10 +93,10 @@ ES6 模块也允许内嵌在网页中,语法行为与加载外部脚本完全 对于外部的模块脚本(上例是`foo.js`),有几点需要注意。 -- 代码是在模块作用域之中运行,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。 -- 模块脚本自动采用严格模式,不管有没有声明`use strict`。 +- 代码是**在模块作用域之中运行**,而不是在全局作用域运行。模块内部的顶层变量,外部不可见。 +- 模块脚本**自动采用严格模式**,不管有没有声明`use strict`。 - 模块之中,可以使用`import`命令加载其他模块(`.js`后缀不可省略,需要提供绝对 URL 或相对 URL),也可以使用`export`命令输出对外接口。 -- 模块之中,顶层的`this`关键字返回`undefined`,而不是指向`window`。也就是说,在模块顶层使用`this`关键字,是无意义的。 +- 模块之中,**顶层的`this`关键字返回`undefined`**,而不是指向`window`。也就是说,在模块顶层使用`this`关键字,是无意义的。 - 同一个模块如果加载多次,将只执行一次。 下面是一个示例模块。 @@ -120,10 +120,10 @@ const isNotModuleScript = this !== undefined; 讨论 Node.js 加载 ES6 模块之前,必须了解 ES6 模块与 CommonJS 模块完全不同。 -它们有两个重大差异。 +它们有**两个重大差异**。 -- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。 -- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。 +- **CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。** +- **CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。** 第二个差异是因为 CommonJS 加载的是一个对象(即`module.exports`属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。 @@ -178,7 +178,7 @@ $ node main.js 4 ``` -ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令`import`,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的`import`有点像 Unix 系统的“符号连接”,原始值变了,`import`加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。 +ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令`import`,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的`import`有点像 Unix 系统的“符号连接”,原始值变了,`import`加载的值也会跟着变。因此,**ES6 模块是动态引用,并且不会缓存值**,模块里面的变量绑定其所在的模块。 还是举上面的例子。 @@ -224,7 +224,7 @@ baz 上面代码表明,ES6 模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。 -由于 ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。 +由于 ES6 输入的模块变量,只是一个“符号连接”,所以**这个变量是只读的,对它进行重新赋值会报错**。 ```javascript // lib.js @@ -287,9 +287,9 @@ $ babel-node main.js Node.js 对 ES6 模块的处理比较麻烦,因为它有自己的 CommonJS 模块格式,与 ES6 模块格式是不兼容的。目前的解决方案是,将两者分开,ES6 模块和 CommonJS 采用各自的加载方案。从 v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。 -Node.js 要求 ES6 模块采用`.mjs`后缀文件名。也就是说,只要脚本文件里面使用`import`或者`export`命令,那么就必须采用`.mjs`后缀名。Node.js 遇到`.mjs`文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定`"use strict"`。 +Node.js 要求 ES6 模块**采用`.mjs`后缀文件名**。也就是说,只要脚本文件里面使用`import`或者`export`命令,那么就必须采用`.mjs`后缀名。Node.js 遇到`.mjs`文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定`"use strict"`。 -如果不希望将后缀名改成`.mjs`,可以在项目的`package.json`文件中,指定`type`字段为`module`。 +**如果不希望将后缀名改成`.mjs`,可以在项目的`package.json`文件中,指定`type`字段为`module`。** ```javascript { @@ -304,11 +304,11 @@ Node.js 要求 ES6 模块采用`.mjs`后缀文件名。也就是说,只要脚 $ node my-app.js ``` -如果这时还要使用 CommonJS 模块,那么需要将 CommonJS 脚本的后缀名都改成`.cjs`。如果没有`type`字段,或者`type`字段为`commonjs`,则`.js`脚本会被解释成 CommonJS 模块。 +如果这时还要使用 CommonJS 模块,那么**需要将 CommonJS 脚本的后缀名都改成`.cjs`。如果没有`type`字段,或者`type`字段为`commonjs`,则`.js`脚本会被解释成 CommonJS 模块**。 -总结为一句话:`.mjs`文件总是以 ES6 模块加载,`.cjs`文件总是以 CommonJS 模块加载,`.js`文件的加载取决于`package.json`里面`type`字段的设置。 +总结为一句话:**`.mjs`文件总是以 ES6 模块加载,`.cjs`文件总是以 CommonJS 模块加载,`.js`文件的加载取决于`package.json`里面`type`字段的设置**。 -注意,ES6 模块与 CommonJS 模块尽量不要混用。`require`命令不能加载`.mjs`文件,会报错,只有`import`命令才可以加载`.mjs`文件。反过来,`.mjs`文件里面也不能使用`require`命令,必须使用`import`。 +注意,ES6 模块与 CommonJS 模块尽量**不要混用**。`require`命令不能加载`.mjs`文件,会报错,只有`import`命令才可以加载`.mjs`文件。反过来,`.mjs`文件里面也不能使用`require`命令,必须使用`import`。 ### main 字段 @@ -333,15 +333,15 @@ import { something } from 'es-module-package'; // 实际加载的是 ./node_modules/es-module-package/src/index.js ``` -上面代码中,运行该脚本以后,Node.js 就会到`./node_modules`目录下面,寻找`es-module-package`模块,然后根据该模块`package.json`的`main`字段去执行入口文件。 +上面代码中,**运行该脚本以后,Node.js 就会到`./node_modules`目录下面,寻找`es-module-package`模块,然后根据该模块`package.json`的`main`字段去执行入口文件。** 这时,如果用 CommonJS 模块的`require()`命令去加载`es-module-package`模块会报错,因为 CommonJS 模块不能处理`export`命令。 ### exports 字段 -`exports`字段的优先级高于`main`字段。它有多种用法。 +**`exports`字段的优先级高于`main`字段**。它有多种用法。 -(1)子目录别名 +(1)**子目录别名** `package.json`文件的`exports`字段可以指定脚本或子目录的别名。 @@ -402,7 +402,7 @@ import submodule from './node_modules/es-module-package/private-module.js'; } ``` -由于`exports`字段只有支持 ES6 的 Node.js 才认识,所以可以用来兼容旧版本的 Node.js。 +**由于`exports`字段只有支持 ES6 的 Node.js 才认识,所以可以用来兼容旧版本的 Node.js**。 ```javascript { diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/25.\347\274\226\347\250\213\351\243\216\346\240\274.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/25.\347\274\226\347\250\213\351\243\216\346\240\274.md" index 8835eadf83..04296b3d18 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/25.\347\274\226\347\250\213\351\243\216\346\240\274.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/25.\347\274\226\347\250\213\351\243\216\346\240\274.md" @@ -53,7 +53,7 @@ if (true) { 在`let`和`const`之间,建议优先使用`const`,尤其是在全局环境,不应该设置变量,只应设置常量。 -`const`优于`let`有几个原因。一个是`const`可以提醒阅读程序的人,这个变量不应该改变;另一个是`const`比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;最后一个原因是 JavaScript 编译器会对`const`进行优化,所以多使用`const`,有利于提高程序的运行效率,也就是说`let`和`const`的本质区别,其实是编译器内部的处理不同。 +`const`优于`let`有几个原因。一个是`const`可以提醒阅读程序的人,这个变量不应该改变;另一个是`const`比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;最后一个原因是 JavaScript **编译器会对`const`进行优化**,所以多使用`const`,有利于提高程序的运行效率,也就是说`let`和`const`的本质区别,其实是编译器内部的处理不同。 ```javascript // bad @@ -143,7 +143,7 @@ const { left, right } = processInput(input); ## 对象 -单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。 +单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,**最后一个成员以逗号结尾**。 ```javascript // bad @@ -197,7 +197,7 @@ const obj = { 上面代码中,对象`obj`的最后一个属性名,需要计算得到。这时最好采用属性表达式,在新建`obj`的时候,将该属性与其他属性定义在一起。这样一来,所有属性就在一个地方定义了。 -另外,对象的属性和方法,尽量采用简洁表达法,这样易于描述和书写。 +另外,对象的属性和方法,**尽量采用简洁表达法**,这样易于描述和书写。 ```javascript var ref = 'some value'; @@ -227,7 +227,7 @@ const atom = { ## 数组 -使用扩展运算符(...)拷贝数组。 +使用**扩展运算符(...)拷贝数组**。 ```javascript // bad @@ -243,7 +243,7 @@ for (i = 0; i < len; i++) { const itemsCopy = [...items]; ``` -使用 Array.from 方法,将类似数组的对象转为数组。 +使用 **Array.from 方法,将类似数组的对象转为数组**。 ```javascript const foo = document.querySelectorAll('.foo'); @@ -260,7 +260,7 @@ const nodes = Array.from(foo); })(); ``` -那些使用匿名函数当作参数的场合,尽量用箭头函数代替。因为这样更简洁,而且绑定了 this。 +那些使用匿名函数当作参数的场合,**尽量用箭头函数代替**。因为这样更简洁,而且绑定了 this。 ```javascript // bad @@ -293,9 +293,9 @@ const boundMethod = method.bind(this); const boundMethod = (...params) => method.apply(this, params); ``` -简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。 +简单的、单行的、不会复用的函数,建议采用箭头函数。**如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。** -所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数。 +**所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数**。 ```javascript // bad diff --git "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/31.\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/31.\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" index 01af4d4d0c..e2ece18d3f 100644 --- "a/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/31.\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" +++ "b/docs/\343\200\212ES6 \346\225\231\347\250\213\343\200\213\347\254\224\350\256\260/31.\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" @@ -16,7 +16,7 @@ ES6 的种种新增功能,使得函数式编程变得更方便、更强大。 ## 柯里化 -柯里化(currying)指的是将一个多参数的函数拆分成一系列函数,每个拆分后的函数都只接受一个参数(unary)。 +**柯里化(currying)指的是将一个多参数的函数拆分成一系列函数,每个拆分后的函数都只接受一个参数**(unary)。 ```javascript function add (a, b) { diff --git a/package.json b/package.json index a68959b7a6..d272bbdf85 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "vuepress-plugin-one-click-copy": "^1.0.2", "vuepress-plugin-thirdparty-search": "^1.0.2", "vuepress-plugin-zooming": "^1.1.7", - "vuepress-theme-vdoing": "^1.3.6", + "vuepress-theme-vdoing": "^1.4.0", "yamljs": "^0.3.0" }, "dependencies": { diff --git a/theme-vdoing/components/BodyBgImg.vue b/theme-vdoing/components/BodyBgImg.vue index c7c1953975..4ed68b2dae 100644 --- a/theme-vdoing/components/BodyBgImg.vue +++ b/theme-vdoing/components/BodyBgImg.vue @@ -1,5 +1,5 @@ diff --git a/theme-vdoing/components/Page.vue b/theme-vdoing/components/Page.vue index 7be8faacbe..7a706f9d5f 100644 --- a/theme-vdoing/components/Page.vue +++ b/theme-vdoing/components/Page.vue @@ -3,7 +3,7 @@
-
+
@@ -57,6 +57,10 @@ export default { this.updateBarConfig = this.$themeConfig.updateBar }, computed: { + bgStyle(){ + const { contentBgStyle } = this.$themeConfig + return contentBgStyle ? 'bg-style-' + contentBgStyle : '' + }, isShowUpdateBar() { return this.updateBarConfig && this.updateBarConfig.showToArticle === false ? false : true }, @@ -100,6 +104,33 @@ export default { max-height 2.2rem +.theme-vdoing-wrapper + --linesColor: rgba(50, 0, 0, 0.05) + &.bg-style-1 // 方格 + background-image: linear-gradient(90deg, var(--linesColor) 3%, transparent 3%), linear-gradient(0deg, var(--linesColor) 3%, transparent 3%) + background-position: center center + background-size: 20px 20px + &.bg-style-2 // 横线 + background-image: repeating-linear-gradient(0, var(--linesColor) 0, var(--linesColor) 1px, transparent 0, transparent 50%); + background-size: 30px 30px + &.bg-style-3 // 竖线 + background-image: repeating-linear-gradient(90deg, var(--linesColor) 0, var(--linesColor) 1px, transparent 0, transparent 50%); + background-size: 30px 30px + &.bg-style-4 // 左斜线 + background-image: repeating-linear-gradient(-45deg, var(--linesColor) 0, var(--linesColor) 1px, transparent 0, transparent 50%); + background-size: 20px 20px + &.bg-style-5 // 右斜线 + background-image: repeating-linear-gradient(45deg, var(--linesColor) 0, var(--linesColor) 1px, transparent 0, transparent 50%); + background-size: 20px 20px + &.bg-style-6 // 点状 + background-image: radial-gradient(var(--linesColor) 1px, transparent 1px); + background-size: 10px 10px + +// 背景纹适应深色模式 +.theme-mode-dark + .theme-vdoing-wrapper + --linesColor: rgba(125,125,125, 0.05) + /** * 右侧菜单的自适应 */ diff --git a/theme-vdoing/package.json b/theme-vdoing/package.json index e1138e392f..95844f4f8e 100644 --- a/theme-vdoing/package.json +++ b/theme-vdoing/package.json @@ -1,6 +1,6 @@ { "name": "vuepress-theme-vdoing", - "version": "1.3.6", + "version": "1.4.0", "description": "Vdoing theme for VuePress. 一个基于VuePress的知识管理兼博客主题。", "author": { "name": "gaoyi(Evan) Xu"