diff --git a/.github/workflows/wangdoc.yml b/.github/workflows/wangdoc.yml
index 80f8bfe..c3e5cbe 100644
--- a/.github/workflows/wangdoc.yml
+++ b/.github/workflows/wangdoc.yml
@@ -10,28 +10,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Node.js
- uses: actions/setup-node@main
+ uses: actions/setup-node@v4
with:
- node-version: '14'
+ node-version: 'latest'
- name: Install dependencies
run: npm install
- name: Build pages
run: npm run build
- name: Deploy to website
- uses: JamesIves/github-pages-deploy-action@3.7.1
+ uses: JamesIves/github-pages-deploy-action@v4
with:
- GIT_CONFIG_NAME: wangdoc-bot
- GIT_CONFIG_EMAIL: yifeng.ruan@gmail.com
- REPOSITORY_NAME: wangdoc/website
- ACCESS_TOKEN: ${{ secrets.WANGDOC_BOT_TOKEN }}
- BASE_BRANCH: master
- BRANCH: master # The branch the action should deploy to.
- FOLDER: dist # The folder the action should deploy.
- TARGET_FOLDER: dist/javascript
- CLEAN: true # Automatically remove deleted files from the deploy branch
- COMMIT_MESSAGE: update from JavaScript tutorial
+ git-config-name: wangdoc-bot
+ git-config-email: yifeng.ruan@gmail.com
+ repository-name: wangdoc/website
+ token: ${{ secrets.WANGDOC_BOT_TOKEN }}
+ branch: master # The branch the action should deploy to.
+ folder: dist # The folder the action should deploy.
+ target-folder: dist/javascript
+ clean: true # Automatically remove deleted files from the deploy branch
+ commit-message: update from JavaScript tutorial
diff --git a/docs/async/general.md b/docs/async/general.md
index a4c9747..a745bfe 100644
--- a/docs/async/general.md
+++ b/docs/async/general.md
@@ -271,7 +271,7 @@ function launcher() {
running--;
if(items.length > 0) {
launcher();
- } else if(running == 0) {
+ } else if(running === 0) {
final(results);
}
});
diff --git a/docs/async/promise.md b/docs/async/promise.md
index 68b5c07..cb629d7 100644
--- a/docs/async/promise.md
+++ b/docs/async/promise.md
@@ -274,7 +274,7 @@ console.log(3);
## 参考链接
-- Sebastian Porto, [Asynchronous JS: Callbacks, Listeners, Control Flow Libs and Promises](http://sporto.github.com/blog/2012/12/09/callbacks-listeners-promises/)
+- Sebastian Porto, [Asynchronous JS: Callbacks, Listeners, Control Flow Libs and Promises](https://sporto.github.io/blog/2012/12/09/callbacks-listeners-promises/)
- Rhys Brett-Bowen, [Promises/A+ - understanding the spec through implementation](http://modernjavascript.blogspot.com/2013/08/promisesa-understanding-by-doing.html)
- Matt Podwysocki, Amanda Silver, [Asynchronous Programming in JavaScript with “Promises”](http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx)
- Marc Harter, [Promise A+ Implementation](https://gist.github.com//wavded/5692344)
diff --git a/docs/basic/grammar.md b/docs/basic/grammar.md
index 1611427..b0dea02 100644
--- a/docs/basic/grammar.md
+++ b/docs/basic/grammar.md
@@ -485,7 +485,7 @@ var msg = '数字' + n + '是' + (n % 2 === 0 ? '偶数' : '奇数');
### while 循环
-`While`语句包括一个循环条件和一段代码块,只要条件为真,就不断循环执行代码块。
+`while`语句包括一个循环条件和一段代码块,只要条件为真,就不断循环执行代码块。
```javascript
while (条件)
@@ -727,4 +727,4 @@ top:
## 参考链接
-- Axel Rauschmayer, [A quick overview of JavaScript](http://www.2ality.com/2011/10/javascript-overview.html)
+- Axel Rauschmayer, [Basic JavaScript for the impatient programmer](https://2ality.com/2013/06/basic-javascript.html)
diff --git a/docs/basic/history.md b/docs/basic/history.md
index 0c03d6d..f5c266b 100644
--- a/docs/basic/history.md
+++ b/docs/basic/history.md
@@ -181,7 +181,7 @@ JavaScript 伴随着互联网的发展一起发展。互联网周边技术的快
## 参考链接
-- Axel Rauschmayer, [The Past, Present, and Future of JavaScript](http://oreilly.com/javascript/radarreports/past-present-future-javascript.csp)
+- Axel Rauschmayer, [The Past, Present, and Future of JavaScript](https://www.oreilly.com/library/view/the-past-present/9781449343545/)
- John Dalziel, [The race for speed part 4: The future for JavaScript](http://creativejs.com/2013/06/the-race-for-speed-part-4-the-future-for-javascript/)
-- Axel Rauschmayer, [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html)
-- resin.io, [Happy 18th Birthday JavaScript! A look at an unlikely past and bright future](http://resin.io/happy-18th-birthday-javascript/)
+- Axel Rauschmayer, [Basic JavaScript for the impatient programmer](https://www.2ality.com/2013/06/basic-javascript.html)
+- balena.io, [Happy 18th Birthday JavaScript! A look at an unlikely past and bright future](https://www.balena.io/blog/happy-18th-birthday-javascript/)
diff --git a/docs/bom/cookie.md b/docs/bom/cookie.md
index 80c542c..e0ae045 100644
--- a/docs/bom/cookie.md
+++ b/docs/bom/cookie.md
@@ -342,7 +342,7 @@ document.cookie = "foo=bar; expires=Fri, 31 Dec 2020 23:59:59 GMT";
各个属性的写入注意点如下。
- `path`属性必须为绝对路径,默认为当前路径。
-- `domain`属性值必须是当前发送 Cookie 的域名的一部分。比如,当前域名是`example.com`,就不能将其设为`foo.com`。该属性默认为当前的一级域名(不含二级域名)。
+- `domain`属性值必须是当前发送 Cookie 的域名的一部分。比如,当前域名是`example.com`,就不能将其设为`foo.com`。该属性默认为当前的一级域名(不含二级域名)。如果显式设置该属性,则该域名的任意子域名也可以读取 Cookie。
- `max-age`属性的值为秒数。
- `expires`属性的值为 UTC 格式,可以使用`Date.prototype.toUTCString()`进行日期格式转换。
@@ -352,9 +352,11 @@ document.cookie = "foo=bar; expires=Fri, 31 Dec 2020 23:59:59 GMT";
document.cookie = 'fontSize=14; '
+ 'expires=' + someDate.toGMTString() + '; '
+ 'path=/subdirectory; '
- + 'domain=*.example.com';
+ + 'domain=example.com';
```
+注意,上面的`domain`属性,以前的写法是`.example.com`,表示子域名也可以读取该 Cookie,新的写法可以省略前面的点。
+
Cookie 的属性一旦设置完成,就没有办法读取这些属性的值。
删除一个现存 Cookie 的唯一方法,是设置它的`expires`属性为一个过去的日期。
diff --git a/docs/bom/cors.md b/docs/bom/cors.md
index 368ea0c..566e1f0 100644
--- a/docs/bom/cors.md
+++ b/docs/bom/cors.md
@@ -1,12 +1,12 @@
# CORS 通信
-CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨域的服务器,发出`XMLHttpRequest`请求,从而克服了 AJAX 只能同源使用的限制。
+CORS 是一个 W3C 标准,全称是“跨源资源共享”(Cross-origin resource sharing),或者通俗地称为“跨域资源共享”。它允许浏览器向跨源的服务器,发出`XMLHttpRequest`请求,从而克服了 AJAX 只能同源使用的限制。
## 简介
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能。
-整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与普通的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信。
+整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与普通的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
## 两种请求
@@ -30,7 +30,7 @@ CORS 请求分成两类:简单请求(simple request)和非简单请求(n
凡是不同时满足上面两个条件,就属于非简单请求。一句话,简单请求就是简单的 HTTP 方法与简单的 HTTP 头信息的结合。
-这样划分的原因是,表单在历史上一直可以跨域发出请求。简单请求就是表单请求,浏览器沿袭了传统的处理方式,不把行为复杂化,否则开发者可能转而使用表单,规避 CORS 的限制。对于非简单请求,浏览器会采用新的处理方式。
+这样划分的原因是,表单在历史上一直可以跨源发出请求。简单请求就是表单请求,浏览器沿袭了传统的处理方式,不把行为复杂化,否则开发者可能转而使用表单,规避 CORS 的限制。对于非简单请求,浏览器会采用新的处理方式。
## 简单请求
@@ -38,7 +38,7 @@ CORS 请求分成两类:简单请求(simple request)和非简单请求(n
对于简单请求,浏览器直接发出 CORS 请求。具体来说,就是在头信息之中,增加一个`Origin`字段。
-下面是一个例子,浏览器发现这次跨域 AJAX 请求是简单请求,就自动在头信息之中,添加一个`Origin`字段。
+下面是一个例子,浏览器发现这次跨源 AJAX 请求是简单请求,就自动在头信息之中,添加一个`Origin`字段。
```http
GET /cors HTTP/1.1
@@ -99,7 +99,7 @@ xhr.withCredentials = true;
xhr.withCredentials = false;
```
-需要注意的是,如果服务器要求浏览器发送 Cookie,`Access-Control-Allow-Origin`就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie 依然遵循同源政策,只有用服务器域名设置的 Cookie 才会上传,其他域名的 Cookie 并不会上传,且(跨域)原网页代码中的`document.cookie`也无法读取服务器域名下的 Cookie。
+需要注意的是,如果服务器要求浏览器发送 Cookie,`Access-Control-Allow-Origin`就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie 依然遵循同源政策,只有用服务器域名设置的 Cookie 才会上传,其他域名的 Cookie 并不会上传,且(跨源)原网页代码中的`document.cookie`也无法读取服务器域名下的 Cookie。
## 非简单请求
@@ -107,7 +107,7 @@ xhr.withCredentials = false;
非简单请求是那种对服务器提出特殊要求的请求,比如请求方法是`PUT`或`DELETE`,或者`Content-Type`字段的类型是`application/json`。
-非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为“预检”请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的`XMLHttpRequest`请求,否则就报错。这是为了防止这些新增的请求,对传统的没有 CORS 支持的服务器形成压力,给服务器一个提前拒绝的机会,这样可以防止服务器收到大量`DELETE`和`PUT`请求,这些传统的表单不可能跨域发出的请求。
+非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为“预检”请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的`XMLHttpRequest`请求,否则就报错。这是为了防止这些新增的请求,对传统的没有 CORS 支持的服务器形成压力,给服务器一个提前拒绝的机会,这样可以防止服务器收到大量`DELETE`和`PUT`请求,这些传统的表单不可能跨源发出的请求。
下面是一段浏览器的 JavaScript 脚本。
@@ -162,7 +162,6 @@ Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
-Content-Type: text/plain
```
上面的 HTTP 回应中,关键的是`Access-Control-Allow-Origin`字段,表示`http://api.bob.com`可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。
@@ -200,7 +199,7 @@ Access-Control-Max-Age: 1728000
**(1)`Access-Control-Allow-Methods`**
-该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次“预检”请求。
+该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨源请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次“预检”请求。
**(2)`Access-Control-Allow-Headers`**
diff --git a/docs/bom/engine.md b/docs/bom/engine.md
index 86e7f53..8c0761e 100644
--- a/docs/bom/engine.md
+++ b/docs/bom/engine.md
@@ -436,4 +436,4 @@ JavaScript 是一种解释型语言,也就是说,它不需要编译,由解
- Axel Rauschmayer, [ECMAScript 6 promises (1/2): foundations](http://www.2ality.com/2014/09/es6-promises-foundations.html)
- Daniel Imms, [async vs defer attributes](http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html)
- Craig Buckler, [Load Non-blocking JavaScript with HTML5 Async and Defer](http://www.sitepoint.com/non-blocking-async-defer/)
-- Domenico De Felice, [How browsers work](http://domenicodefelice.blogspot.sg/2015/08/how-browsers-work.html?t=2)
+- Domenico De Felice, [How browsers work](https://domenicodefelice.blogspot.com/2015/08/how-browsers-work.html)
diff --git a/docs/bom/same-origin.md b/docs/bom/same-origin.md
index 50577ce..4a11a0b 100644
--- a/docs/bom/same-origin.md
+++ b/docs/bom/same-origin.md
@@ -194,7 +194,7 @@ window.addEventListener('message', function (e) {
`message`事件的参数是事件对象`event`,提供以下三个属性。
> - `event.source`:发送消息的窗口
-> - `event.origin`: 消息发向的网址
+> - `event.origin`: 消息发送者的源(origin),即协议、域名、端口。
> - `event.data`: 消息内容
下面的例子是,子窗口通过`event.source`属性引用父窗口,然后发送消息。
@@ -208,7 +208,7 @@ function receiveMessage(event) {
上面代码有几个地方需要注意。首先,`receiveMessage`函数里面没有过滤信息的来源,任意网址发来的信息都会被处理。其次,`postMessage`方法中指定的目标窗口的网址是一个星号,表示该信息可以向任意网址发送。通常来说,这两种做法是不推荐的,因为不够安全,可能会被恶意利用。
-`event.origin`属性可以过滤不是发给本窗口的消息。
+`event.origin`属性可以过滤非许可地址发来的消息。
```javascript
window.addEventListener('message', receiveMessage);
diff --git a/docs/bom/window.md b/docs/bom/window.md
index a012d61..a873fae 100644
--- a/docs/bom/window.md
+++ b/docs/bom/window.md
@@ -579,7 +579,7 @@ var start = null;
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
- // 元素不断向左移,最大不超过200像素
+ // 元素不断向右移,最大不超过200像素
element.style.left = Math.min(progress / 10, 200) + 'px';
// 如果距离第一次执行不超过 2000 毫秒,
// 就继续执行动画
diff --git a/docs/bom/xmlhttprequest.md b/docs/bom/xmlhttprequest.md
index 8855064..66f662c 100644
--- a/docs/bom/xmlhttprequest.md
+++ b/docs/bom/xmlhttprequest.md
@@ -743,7 +743,7 @@ window.addEventListener('unload', function(event) {
上面代码中,强制执行了一次双重循环,拖长了`unload`事件的执行时间,导致异步 AJAX 能够发送成功。
-类似的还可以使用`setTimeout`。下面是追踪用户点击的例子。
+类似的还可以使用`setTimeout()`。下面是追踪用户点击的例子。
```javascript
// HTML 代码如下
@@ -768,7 +768,7 @@ theLink.addEventListener('click', function (event) {
});
```
-上面代码使用`setTimeout`,拖延了350毫秒,才让页面跳转,因此使得异步 AJAX 有时间发出。
+上面代码使用`setTimeout()`,拖延了350毫秒,才让页面跳转,因此使得异步 AJAX 有时间发出。
这些做法的共同问题是,卸载的时间被硬生生拖长了,后面页面的加载被推迟了,用户体验不好。
@@ -778,11 +778,13 @@ theLink.addEventListener('click', function (event) {
window.addEventListener('unload', logData, false);
function logData() {
- navigator.sendBeacon('/log', analyticsData);
+ navigator.sendBeacon('/log', JSON.stringify({
+ some: "data"
+ }));
}
```
-`Navigator.sendBeacon`方法接受两个参数,第一个参数是目标服务器的 URL,第二个参数是所要发送的数据(可选),可以是任意类型(字符串、表单对象、二进制对象等等)。
+`Navigator.sendBeacon()`方法接受两个参数,第一个参数是目标服务器的 URL,第二个参数是所要发送的数据(可选),可以是任意类型(字符串、表单对象、二进制对象等等)。
```javascript
navigator.sendBeacon(url, data)
@@ -806,3 +808,16 @@ function analytics(state) {
navigator.sendBeacon(URL, data);
}
```
+
+该方法不允许自定义 HTTP 标头,为了以“application/json”的形式发送数据,可以使用 Blob 对象。
+
+```javascript
+const blob = new Blob(
+ [ JSON.stringify({ some: "data" }) ],
+ { type: 'application/json; charset=UTF-8' }
+);
+navigator.sendBeacon('/log', blob));
+```
+
+这个方法的优先级较低,不会占用页面资源。一般是在浏览器空闲的时候,才会发送。
+
diff --git a/docs/dom/css.md b/docs/dom/css.md
index 5a1d39a..b4f1a2d 100644
--- a/docs/dom/css.md
+++ b/docs/dom/css.md
@@ -292,7 +292,7 @@ CSS.supports('display: table-cell;') // false
行内样式(inline style)具有最高的优先级,改变行内样式,通常会立即反映出来。但是,网页元素最终的样式是综合各种规则计算出来的。因此,如果想得到元素实际的样式,只读取行内样式是不够的,需要得到浏览器最终计算出来的样式规则。
-`window.getComputedStyle`方法,就用来返回浏览器计算后得到的最终规则。它接受一个节点对象作为参数,返回一个 CSSStyleDeclaration 实例,包含了指定节点的最终样式信息。所谓“最终样式信息”,指的是各种 CSS 规则叠加后的结果。
+`window.getComputedStyle()`方法,就用来返回浏览器计算后得到的最终规则。它接受一个节点对象作为参数,返回一个 CSSStyleDeclaration 实例,包含了指定节点的最终样式信息。所谓“最终样式信息”,指的是各种 CSS 规则叠加后的结果。
```javascript
var div = document.querySelector('div');
@@ -328,7 +328,7 @@ var height = styleObj.getPropertyValue('height');
- CSSStyleDeclaration 实例返回的 CSS 值都是绝对单位。比如,长度都是像素单位(返回值包括`px`后缀),颜色是`rgb(#, #, #)`或`rgba(#, #, #, #)`格式。
- CSS 规则的简写形式无效。比如,想读取`margin`属性的值,不能直接读,只能读`marginLeft`、`marginTop`等属性;再比如,`font`属性也是不能直接读的,只能读`font-size`等单个属性。
- 如果读取 CSS 原始的属性名,要用方括号运算符,比如`styleObj['z-index']`;如果读取骆驼拼写法的 CSS 属性名,可以直接读取`styleObj.zIndex`。
-- 该方法返回的 CSSStyleDeclaration 实例的`cssText`属性无效,返回`undefined`。
+- 该方法返回的 CSSStyleDeclaration 实例的`cssText`属性总是返回空字符串。
## CSS 伪元素
@@ -401,9 +401,9 @@ myStyleSheet instanceof StyleSheet // true
注意,`disabled`属性只能在 JavaScript 脚本中设置,不能在 HTML 语句中设置。
-**(2)Stylesheet.href**
+**(2)StyleSheet.href**
-`Stylesheet.href`返回样式表的网址。对于内嵌样式表,该属性返回`null`。该属性只读。
+`StyleSheet.href`返回样式表的网址。对于内嵌样式表,该属性返回`null`。该属性只读。
```javascript
document.styleSheets[0].href
diff --git a/docs/dom/document.md b/docs/dom/document.md
index 3eb1d02..7af7f3a 100644
--- a/docs/dom/document.md
+++ b/docs/dom/document.md
@@ -69,7 +69,10 @@ document.scrollingElement.scrollTop = 0;
`document.fullscreenElement`属性返回当前以全屏状态展示的 DOM 元素。如果不是全屏状态,该属性返回`null`。
```javascript
-if (document.fullscreenElement.nodeName == 'VIDEO') {
+if (
+ document.fullscreenElement &&
+ document.fullscreenElement.nodeName == 'VIDEO'
+) {
console.log('全屏播放视频');
}
```
@@ -363,7 +366,7 @@ document.replaceChild(
);
```
-上面代码中,第一步生成一个新的 HTML 文档`doc`,然后用它的根元素`document.documentElement`替换掉`document.documentElement`。这会使得当前文档的内容全部消失,变成`hello world`。
+上面代码中,第一步生成一个新的 HTML 文档`doc`,然后用它的根元素`doc.documentElement`替换掉`document.documentElement`。这会使得当前文档的内容全部消失,变成`hello world`。
## 方法
@@ -716,7 +719,7 @@ var element = document.getElementById('ul');
element.appendChild(docfrag);
```
-上面代码中,文档片断`docfrag`包含四个`
`节点,这些子节点被一次性插入了当前文档。
+上面代码中,文档片段`docfrag`包含四个``节点,这些子节点被一次性插入了当前文档。
### document.createEvent()
diff --git a/docs/dom/element.md b/docs/dom/element.md
index 2b5ea6d..6a73887 100644
--- a/docs/dom/element.md
+++ b/docs/dom/element.md
@@ -371,8 +371,8 @@ document.body.scrollHeight
```javascript
// HTML 代码如下
-// ...
-document.getElementById('myDiv').scrollHeight // 356
+//
...
+document.getElementById('myDiv').scrollHeight // 200
```
上面代码中,即使`myDiv`元素的 CSS 高度只有200像素,且溢出部分不可见,但是`scrollHeight`仍然会返回该元素的原始高度。
diff --git a/docs/dom/mutationobserver.md b/docs/dom/mutationobserver.md
index ace5853..0715565 100644
--- a/docs/dom/mutationobserver.md
+++ b/docs/dom/mutationobserver.md
@@ -44,7 +44,7 @@ var observer = new MutationObserver(function (mutations, observer) {
```javascript
var article = document.querySelector('article');
-var options = {
+var options = {
'childList': true,
'attributes':true
} ;
diff --git a/docs/elements/input.md b/docs/elements/input.md
index 9a04e0e..fce544a 100644
--- a/docs/elements/input.md
+++ b/docs/elements/input.md
@@ -75,7 +75,18 @@
- `labels`:返回一个`NodeList`实例,代表绑定当前`
`节点的`