From 87d5dedb2d4f34682209884489ae5b7248e1b001 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 9 May 2023 14:00:30 +0800 Subject: [PATCH 01/38] docs(style): edit text --- docs/style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/style.md b/docs/style.md index fc23e2ffa..95fe4c92e 100644 --- a/docs/style.md +++ b/docs/style.md @@ -285,7 +285,7 @@ const boundMethod = (...params) => method.apply(this, params); 简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。 -所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数。 +所有配置项都应该集中在一个对象,放在最后一个参数,布尔值最好不要直接作为参数,因为代码语义会很差,也不利于将来增加其他配置项。 ```javascript // bad From 982f4983a9a178d6eb78b92b1dd2b9496bf0f8e5 Mon Sep 17 00:00:00 2001 From: qijizh Date: Mon, 15 May 2023 02:51:11 +0800 Subject: [PATCH 02/38] docs(generator): update example --- docs/generator.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/generator.md b/docs/generator.md index 7d18278ca..283b84484 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -552,26 +552,26 @@ g.throw(1); 上面代码中,`g.throw(1)`执行时,`next`方法一次都没有执行过。这时,抛出的错误不会被内部捕获,而是直接在外部抛出,导致程序出错。这种行为其实很好理解,因为第一次执行`next`方法,等同于启动执行 Generator 函数的内部代码,否则 Generator 函数还没有开始执行,这时`throw`方法抛错只可能抛出在函数外部。 -`throw`方法被捕获以后,会附带执行下一条`yield`表达式。也就是说,会附带执行一次`next`方法。 +`throw`方法被内部捕获以后,会附带执行到下一条`yield`表达式,这种情况下等同于执行一次`next`方法。 ```javascript var gen = function* gen(){ try { - yield console.log('a'); + yield 1; } catch (e) { - // ... + yield 2; } - yield console.log('b'); - yield console.log('c'); + yield 3; } var g = gen(); -g.next() // a -g.throw() // b -g.next() // c +g.next() // { value:1, done:false } +g.throw() // { value:2, done:false } +g.next() // { value:3, done:false } +g.next() // { value:undefined, done:true } ``` -上面代码中,`g.throw`方法被捕获以后,自动执行了一次`next`方法,所以会打印`b`。另外,也可以看到,只要 Generator 函数内部部署了`try...catch`代码块,那么遍历器的`throw`方法抛出的错误,不影响下一次遍历。 +上面代码中,`g.throw`方法被内部捕获以后,等同于执行了一次`next`方法,所以返回`{ value:2, done:false }`。另外,也可以看到,只要 Generator 函数内部部署了`try...catch`代码块,那么遍历器的`throw`方法抛出的错误,不影响下一次遍历。 另外,`throw`命令与`g.throw`方法是无关的,两者互不影响。 From 43222de51b3574f98e217364f0c271ca2cce46a2 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 6 Jun 2023 16:14:47 +0800 Subject: [PATCH 03/38] docs(set-map): fixed #1155 --- docs/set-map.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/set-map.md b/docs/set-map.md index da23a6894..cb21460d8 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -118,7 +118,7 @@ s.delete(2) // true s.has(2) // false ``` -下面是一个对比,看看在判断是否包括一个键上面,`Object`结构和`Set`结构的写法不同。 +下面是一个对比,判断是否包括一个键,`Object`结构和`Set`结构写法的不同。 ```javascript // 对象的写法 @@ -142,7 +142,7 @@ if (properties.has(someName)) { } ``` -`Array.from`方法可以将 Set 结构转为数组。 +`Array.from()`方法可以将 Set 结构转为数组。 ```javascript const items = new Set([1, 2, 3, 4, 5]); From 4e4058291619a07ff6e90b2702fcbf3c67cf316a Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 15 Jun 2023 13:18:56 +0800 Subject: [PATCH 04/38] docs(module): fixed #1157 --- docs/module.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/module.md b/docs/module.md index 0f2481587..5d68da67a 100644 --- a/docs/module.md +++ b/docs/module.md @@ -162,6 +162,8 @@ function f() {} export {f}; ``` +目前,export 命令能够对外输出的就是三种接口:函数(Functions), 类(Classes),var、let、const 声明的变量(Variables)。 + 另外,`export`语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。 ```javascript From 7dbca2b4bd469ec7577ea7dc101181b6d051fdaf Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 27 Jun 2023 15:03:55 +0800 Subject: [PATCH 05/38] docs(class): edit text --- docs/class.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class.md b/docs/class.md index cbdde3bbf..a37947a63 100644 --- a/docs/class.md +++ b/docs/class.md @@ -1006,7 +1006,7 @@ class Foo {} } ``` -上面的代码不会报错,因为`Bar`继承`Foo`的时候,`Foo`已经有定义了。但是,如果存在`class`的提升,上面代码就会报错,因为`class`会被提升到代码头部,而`let`命令是不提升的,所以导致`Bar`继承`Foo`的时候,`Foo`还没有定义。 +上面的代码不会报错,因为`Bar`继承`Foo`的时候,`Foo`已经有定义了。但是,如果存在`class`的提升,上面代码就会报错,因为`class`会被提升到代码头部,而定义`Foo`的那一行没有提升,导致`Bar`继承`Foo`的时候,`Foo`还没有定义。 ### name 属性 From a342ebff148fb81ed01f49f56a603ee36cfd6a3d Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 13 Jul 2023 16:27:54 +0800 Subject: [PATCH 06/38] docs(class): fix private field #1159 --- docs/class.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/class.md b/docs/class.md index a37947a63..c27bb2f4a 100644 --- a/docs/class.md +++ b/docs/class.md @@ -844,7 +844,7 @@ class C { } ``` -上面示例中,`in`运算符判断某个对象是否有私有属性`#foo`。它不会报错,而是返回一个布尔值。 +上面示例中,`in`运算符判断某个对象是否有私有属性`#brand`。它不会报错,而是返回一个布尔值。 这种用法的`in`,也可以跟`this`一起配合使用。 @@ -853,12 +853,21 @@ class A { #foo = 0; m() { console.log(#foo in this); // true - console.log(#bar in this); // false } } ``` -注意,判断私有属性时,`in`只能用在类的内部。 +注意,判断私有属性时,`in`只能用在类的内部。另外,判断所针对的私有属性,一定要先声明,否则会报错。 + +```javascript +class A { + m() { + console.log(#foo in this); // 报错 + } +} +``` + +上面示例中,私有属性`#foo`没有声明,就直接用于`in`运算符的判断,导致报错。 子类从父类继承的私有属性,也可以使用`in`运算符来判断。 From ece963d6ab2ab7ea8337a74de61b660a83bc1fee Mon Sep 17 00:00:00 2001 From: succyag <104663431+succyag@users.noreply.github.com> Date: Sun, 16 Jul 2023 21:46:01 +0800 Subject: [PATCH 07/38] Update regex.md --- docs/regex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/regex.md b/docs/regex.md index 157778a99..6ea589a41 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -376,7 +376,7 @@ JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先 ```javascript /(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"] -/(? Date: Mon, 17 Jul 2023 08:12:51 +0800 Subject: [PATCH 08/38] Update regex.md --- docs/regex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/regex.md b/docs/regex.md index 6ea589a41..729eab3c4 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -376,7 +376,7 @@ JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先 ```javascript /(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill') // ["100"] -/(? Date: Thu, 20 Jul 2023 14:38:25 +0800 Subject: [PATCH 09/38] docs(array): fix .group() #1161 --- docs/array.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/array.md b/docs/array.md index 8c2b69000..d12d4a38e 100644 --- a/docs/array.md +++ b/docs/array.md @@ -941,7 +941,7 @@ array.group((num, index, array) => { 下面是另一个例子。 ```javascript -[6.1, 4.2, 6.3].groupBy(Math.floor) +[6.1, 4.2, 6.3].group(Math.floor) // { '4': [4.2], '6': [6.1, 6.3] } ``` From d47a259b1335b609cafcb63039ed7c4969782326 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 26 Jul 2023 19:06:24 +0800 Subject: [PATCH 10/38] docs(set-map): fix Symbol() as WeakSet/WeakMap key #1162 --- docs/set-map.md | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/docs/set-map.md b/docs/set-map.md index cb21460d8..c5fa699ee 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -308,17 +308,15 @@ set = new Set(Array.from(set, val => val * 2)); WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。 -首先,WeakSet 的成员只能是对象,而不能是其他类型的值。 +首先,WeakSet 的成员只能是对象和 Symbol 值,而不能是其他类型的值。 ```javascript const ws = new WeakSet(); -ws.add(1) -// TypeError: Invalid value used in weak set -ws.add(Symbol()) -// TypeError: invalid value used in weak set +ws.add(1) // 报错 +ws.add(Symbol()) // 不报错 ``` -上面代码试图向 WeakSet 添加一个数值和`Symbol`值,结果报错,因为 WeakSet 只能放置对象。 +上面代码试图向 WeakSet 添加一个数值和`Symbol`值,结果前者报错了,因为 WeakSet 只能放置对象和 Symbol 值。 其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。 @@ -633,7 +631,7 @@ m.has(undefined) // true **(5)Map.prototype.delete(key)** -`delete`方法删除某个键,返回`true`。如果删除失败,返回`false`。 +`delete()`方法删除某个键,返回`true`。如果删除失败,返回`false`。 ```javascript const m = new Map(); @@ -646,7 +644,7 @@ m.has(undefined) // false **(6)Map.prototype.clear()** -`clear`方法清除所有成员,没有返回值。 +`clear()`方法清除所有成员,没有返回值。 ```javascript let map = new Map(); @@ -928,21 +926,16 @@ wm2.get(k2) // "bar" `WeakMap`与`Map`的区别有两点。 -首先,`WeakMap`只接受对象作为键名(`null`除外),不接受其他类型的值作为键名。 +首先,`WeakMap`只接受对象(`null`除外)和 [Symbol 值](https://github.com/tc39/proposal-symbols-as-weakmap-keys)作为键名,不接受其他类型的值作为键名。 ```javascript const map = new WeakMap(); -map.set(1, 2) -// TypeError: 1 is not an object! -map.set(Symbol(), 2) -// TypeError: Invalid value used as weak map key -map.set(null, 2) -// TypeError: Invalid value used as weak map key +map.set(1, 2) // 报错 +map.set(null, 2) // 报错 +map.set(Symbol(), 2) // 不报错 ``` -上面代码中,如果将数值`1`和`Symbol`值作为 WeakMap 的键名,都会报错。 - -不过,现在有一个[提案](https://github.com/tc39/proposal-symbols-as-weakmap-keys),允许 Symbol 值也可以作为 WeakMap 的键名。一旦纳入标准,就意味着键名存在两种可能:对象和 Symbol 值。 +上面代码中,如果将数值`1`和`null`作为 WeakMap 的键名,都会报错,将 Symbol 值作为键名不会报错。 其次,`WeakMap`的键名所指向的对象,不计入垃圾回收机制。 From 45614204906bdc55902d7199662b8f7df7922782 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 7 Aug 2023 12:00:15 +0800 Subject: [PATCH 11/38] doc: edit README --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 84de1b82f..2db96d7af 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,30 @@ # ES6 入门教程 -官方镜像:[网道(WangDoc.com)](https://wangdoc.com/es6/) - 《ECMAScript 6 入门教程》是一本开源的 JavaScript 语言教程,全面介绍 ECMAScript 6 新引入的语法特性。 [![cover](images/cover_thumbnail_3rd.jpg)](images/cover-3rd.jpg) 本书覆盖 ES6 与上一个版本 ES5 的所有不同之处,对涉及的语法知识给予详细介绍,并给出大量简洁易懂的示例代码。 -本书为中级难度,适合已经掌握 ES5 的读者,用来了解这门语言的最新发展;也可当作参考手册,查寻新增的语法点。如果你是 JavaScript 语言的初学者,建议先学完[《JavaScript 语言入门教程》](https://wangdoc.com/javascript/),再来看本书。 - -全书已由电子工业出版社出版,2017年9月推出了第三版,书名为《ES6 标准入门》。纸版是基于网站内容排版印刷的。 +本书为中级难度,适合已经掌握 ES5 的读者,用来了解这门语言的最新发展;也可当作参考手册,查寻新增的语法点。如果你是 JavaScript 语言的初学者,建议先学完[《JavaScript 语言教程》](https://wangdoc.com/javascript/),再来看本书。 -感谢张春雨编辑支持我将全书开源的做法。如果您认可这本书,建议购买纸版。这样可以使出版社不因出版开源书籍而亏钱,进而鼓励更多的作者开源自己的书籍。下面是第三版的购买地址。 +全书已由电子工业出版社出版,2017年9月推出了第三版,书名为《ES6 标准入门》。纸版内容截止到出版时,网站内容一直在修订。 - [淘宝](https://s.taobao.com/search?q=ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8+%E7%AC%AC3%E7%89%88) - [京东](https://search.jd.com/Search?keyword=ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8%20%E7%AC%AC3%E7%89%88&enc=utf-8&wq=ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8%20%E7%AC%AC3%E7%89%88) - [当当](https://product.dangdang.com/25156888.html) -- [亚马逊](https://www.amazon.cn/ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8-%E9%98%AE%E4%B8%80%E5%B3%B0/dp/B0755547ZZ) -- [China-pub](http://product.china-pub.com/6504650) -### 版权许可 +## 相关链接 + +- [官方镜像](https://wangdoc.com/es6/) +- [JavaScript 教程](https://wangdoc.com/javascript) +- [TypeScript 教程](https://wangdoc.com/typescript) + +## 版权许可 本书采用“保持署名—非商用”创意共享4.0许可证。 只要保持原作者署名和非商用,您可以自由地阅读、分享、修改本书。 详细的法律条文请参见[创意共享](http://creativecommons.org/licenses/by-nc/4.0/)网站。 + From 16f567b074060d84223b324b956f61f2ec3ab9af Mon Sep 17 00:00:00 2001 From: ruanyf Date: Mon, 7 Aug 2023 12:03:50 +0800 Subject: [PATCH 12/38] doc: edit README --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2db96d7af..5bb40d336 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # ES6 入门教程 +- [官方镜像](https://wangdoc.com/es6/) +- [JavaScript 教程](https://wangdoc.com/javascript) +- [TypeScript 教程](https://wangdoc.com/typescript) + 《ECMAScript 6 入门教程》是一本开源的 JavaScript 语言教程,全面介绍 ECMAScript 6 新引入的语法特性。 [![cover](images/cover_thumbnail_3rd.jpg)](images/cover-3rd.jpg) @@ -14,13 +18,7 @@ - [京东](https://search.jd.com/Search?keyword=ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8%20%E7%AC%AC3%E7%89%88&enc=utf-8&wq=ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8%20%E7%AC%AC3%E7%89%88) - [当当](https://product.dangdang.com/25156888.html) -## 相关链接 - -- [官方镜像](https://wangdoc.com/es6/) -- [JavaScript 教程](https://wangdoc.com/javascript) -- [TypeScript 教程](https://wangdoc.com/typescript) - -## 版权许可 +### 版权许可 本书采用“保持署名—非商用”创意共享4.0许可证。 From 1b9a0ccfe00b1c3b02eb5982dd6e71b803f52dd0 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 19 Aug 2023 15:31:01 +0800 Subject: [PATCH 13/38] docs(class): add Chrome 111 devtool supporting private field access --- docs/class.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/class.md b/docs/class.md index c27bb2f4a..4a2d53af8 100644 --- a/docs/class.md +++ b/docs/class.md @@ -681,6 +681,8 @@ counter.#count = 42 // 报错 上面示例中,在类的外部,读取或写入私有属性`#count`,都会报错。 +注意,[从 Chrome 111 开始](https://developer.chrome.com/blog/new-in-devtools-111/#misc),开发者工具里面可以读写私有属性,不会报错,原因是 Chrome 团队认为这样方便调试。 + 另外,不管在类的内部或外部,读取一个不存在的私有属性,也都会报错。这跟公开属性的行为完全不同,如果读取一个不存在的公开属性,不会报错,只会返回`undefined`。 ```javascript From e8c2d2ea7fcdc36c61c90b067af52407e46f1bf8 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 19 Aug 2023 16:07:40 +0800 Subject: [PATCH 14/38] docs(decorator): fixed #1165 --- docs/decorator.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/decorator.md b/docs/decorator.md index 0577d18b3..3a46d7119 100644 --- a/docs/decorator.md +++ b/docs/decorator.md @@ -129,8 +129,6 @@ MyClass.isTestable // false 上面代码中,装饰器`testable`可以接受参数,这就等于可以修改装饰器的行为。 -注意,装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数。 - 前面的例子是为类添加一个静态属性,如果想添加实例属性,可以通过目标类的`prototype`对象操作。 ```javascript From 4c06dfbfca63d1c09b07d21374add98f72175848 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 22 Aug 2023 18:57:53 +0800 Subject: [PATCH 15/38] docs(symbol): fixed #1166 Symbol.toStringTag --- docs/symbol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/symbol.md b/docs/symbol.md index 2297e10d5..281c81873 100644 --- a/docs/symbol.md +++ b/docs/symbol.md @@ -846,7 +846,7 @@ String(obj) // 'str' ### Symbol.toStringTag -对象的`Symbol.toStringTag`属性,指向一个方法。在该对象上面调用`Object.prototype.toString`方法时,如果这个属性存在,它的返回值会出现在`toString`方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制`[object Object]`或`[object Array]`中`object`后面的那个字符串。 +对象的`Symbol.toStringTag`属性,返回一个字符串。在目标对象上面调用`Object.prototype.toString`方法时,如果`Symbol.toStringTag`属性存在,它的返回值会出现在`toString`方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制`[object Object]`或`[object Array]`中`object`后面的那个字符串。 ```javascript // 例一 From b1b35cde31aa38b1a2e9b7fd330f993a1995d534 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 24 Aug 2023 14:01:03 +0800 Subject: [PATCH 16/38] docs(symbol): edit Symbol.toStringTag #1166 --- docs/symbol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/symbol.md b/docs/symbol.md index 281c81873..4693410b0 100644 --- a/docs/symbol.md +++ b/docs/symbol.md @@ -846,7 +846,7 @@ String(obj) // 'str' ### Symbol.toStringTag -对象的`Symbol.toStringTag`属性,返回一个字符串。在目标对象上面调用`Object.prototype.toString`方法时,如果`Symbol.toStringTag`属性存在,它的返回值会出现在`toString`方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制`[object Object]`或`[object Array]`中`object`后面的那个字符串。 +对象的`Symbol.toStringTag`属性,用来设定一个字符串(设为其他类型的值无效,但不报错)。在目标对象上面调用`Object.prototype.toString()`方法时,如果`Symbol.toStringTag`属性存在,该属性设定的字符串会出现在`toString()`方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制`[object Object]`或`[object Array]`中`object`后面的那个大写字符串。 ```javascript // 例一 From 17246d85bb9e4364adc787d097ce1a158daf84ec Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 24 Aug 2023 14:20:57 +0800 Subject: [PATCH 17/38] docs(proxy): fixed #1167 Proxy get() --- docs/proxy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/proxy.md b/docs/proxy.md index a65ec7dcc..5885094b4 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -286,7 +286,7 @@ const proxy = new Proxy({}, { proxy.getReceiver === proxy // true ``` -上面代码中,`proxy`对象的`getReceiver`属性是由`proxy`对象提供的,所以`receiver`指向`proxy`对象。 +上面代码中,`proxy`对象的`getReceiver`属性会被`get()`拦截,得到的返回值就是`proxy`对象。 ```javascript const proxy = new Proxy({}, { From a623e19fb97f6dbefa25f5c5fa554160103e1bf3 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 9 Nov 2023 19:38:57 +0800 Subject: [PATCH 18/38] docs(intro): fix #1170 --- docs/intro.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/intro.md b/docs/intro.md index 880cf08b7..ea1695911 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -68,9 +68,9 @@ ES6 从开始制定到最后发布,整整用了 15 年。 2015 年 6 月,ECMAScript 6 正式通过,成为国际标准。从 2000 年算起,这时已经过去了 15 年。 -目前,各大浏览器对 ES6 的支持可以查看[kangax.github.io/compat-table/es6/](https://kangax.github.io/compat-table/es6/)。 +目前,各大浏览器对 ES6 的支持可以查看[https://compat-table.github.io/compat-table/es6/](https://compat-table.github.io/compat-table/es6/)。 -Node.js 是 JavaScript 的服务器运行环境(runtime)。它对 ES6 的支持度更高。除了那些默认打开的功能,还有一些语法功能已经实现了,但是默认没有打开。使用下面的命令,可以查看 Node.js 默认没有打开的 ES6 实验性语法。 +Node.js 是 JavaScript 的服务器运行环境(runtime)。它对 ES6 的支持度更高。除了那些默认打开的功能,还有一些语法功能已经实现了,但是默认没有打开。使用下面的命令,可以查看 Node.js 默认没有打开的实验性语法。 ```bash // Linux & Mac From fc58b0c1505654bde876ace4f8f1f7f5882876fa Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 30 Dec 2023 14:42:23 +0800 Subject: [PATCH 19/38] docs(class-extends): fix typo --- docs/class-extends.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/class-extends.md b/docs/class-extends.md index 5b1ff61fd..c5308bd0c 100644 --- a/docs/class-extends.md +++ b/docs/class-extends.md @@ -183,7 +183,7 @@ B.hello() // hello world 上面代码中,`hello()`是`A`类的静态方法,`B`继承`A`,也继承了`A`的静态方法。 -注意,静态属性是通过软拷贝实现继承的。 +注意,静态属性是通过浅拷贝实现继承的。 ```javascript class A { static foo = 100; } From 79e15346b255485dfe3e89a686dfe1de2460433e Mon Sep 17 00:00:00 2001 From: liliangrong777 <58727146+liliangrong777@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:32:06 +0800 Subject: [PATCH 20/38] Update module-loader.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 内容修正 --- docs/module-loader.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/module-loader.md b/docs/module-loader.md index ce8082cc1..ecea1157c 100644 --- a/docs/module-loader.md +++ b/docs/module-loader.md @@ -397,7 +397,7 @@ import submodule from './node_modules/es-module-package/private-module.js'; } ``` -由于`exports`字段只有支持 ES6 的 Node.js 才认识,所以可以用来兼容旧版本的 Node.js。 +由于`exports`字段只有支持 ES6 的 Node.js 才认识,所以可以用`main`字段来兼容旧版本的 Node.js。 ```javascript { From bae421dcdf73fdf71214b148358e44a0388e7fa5 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 10 Apr 2024 18:04:27 +0800 Subject: [PATCH 21/38] docs(module-loader): edit text --- docs/module-loader.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/module-loader.md b/docs/module-loader.md index ecea1157c..31dd685e7 100644 --- a/docs/module-loader.md +++ b/docs/module-loader.md @@ -397,7 +397,7 @@ import submodule from './node_modules/es-module-package/private-module.js'; } ``` -由于`exports`字段只有支持 ES6 的 Node.js 才认识,所以可以用`main`字段来兼容旧版本的 Node.js。 +由于`exports`字段只有支持 ES6 的 Node.js 才认识,所以可以搭配`main`字段,来兼容旧版本的 Node.js。 ```javascript { From 9324fdabefc5a0249a7491fe33dd896ea05c004b Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 15 May 2024 13:57:19 +0800 Subject: [PATCH 22/38] =?UTF-8?q?docs(regex):=20=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=20Emoji=20=E5=AD=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/regex.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/regex.md b/docs/regex.md index 729eab3c4..87c3410a0 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -464,6 +464,9 @@ regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true // 匹配所有空格 \p{White_Space} +// 匹配十六进制字符 +\p{Hex_Digit} + // 匹配各种文字的所有字母,等同于 Unicode 版的 \w [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}] @@ -471,7 +474,7 @@ regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true [^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}] // 匹配 Emoji -/\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu +/\p{Extended_Pictographic}/u // 匹配所有的箭头字符 const regexArrows = /^\p{Block=Arrows}+$/u; From 9c0896c68317e60c3703e69e595fc88a7fca6bfa Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 22 May 2024 12:24:13 +0800 Subject: [PATCH 23/38] =?UTF-8?q?docs(class):=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=8F=8F=E8=BF=B0=EF=BC=88in=20=E8=BF=90?= =?UTF-8?q?=E7=AE=97=E7=AC=A6=E5=88=A4=E6=96=AD=E7=BB=A7=E6=89=BF=E7=9A=84?= =?UTF-8?q?=E7=A7=81=E6=9C=89=E5=B1=9E=E6=80=A7=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/class.md | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/docs/class.md b/docs/class.md index 4a2d53af8..0906a0fe9 100644 --- a/docs/class.md +++ b/docs/class.md @@ -871,46 +871,6 @@ class A { 上面示例中,私有属性`#foo`没有声明,就直接用于`in`运算符的判断,导致报错。 -子类从父类继承的私有属性,也可以使用`in`运算符来判断。 - -```javascript -class A { - #foo = 0; - static test(obj) { - console.log(#foo in obj); - } -} - -class SubA extends A {}; - -A.test(new SubA()) // true -``` - -上面示例中,`SubA`从父类继承了私有属性`#foo`,`in`运算符也有效。 - -注意,`in`运算符对于`Object.create()`、`Object.setPrototypeOf`形成的继承,是无效的,因为这种继承不会传递私有属性。 - -```javascript -class A { - #foo = 0; - static test(obj) { - console.log(#foo in obj); - } -} -const a = new A(); - -const o1 = Object.create(a); -A.test(o1) // false -A.test(o1.__proto__) // true - -const o2 = {}; -Object.setPrototypeOf(o2, a); -A.test(o2) // false -A.test(o2.__proto__) // true -``` - -上面示例中,对于修改原型链形成的继承,子类都取不到父类的私有属性,所以`in`运算符无效。 - ## 静态块 静态属性的一个问题是,如果它有初始化逻辑,这个逻辑要么写在类的外部,要么写在`constructor()`方法里面。 From 642a4ab3e7954ea391db4709558b91e5b2d777ed Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 8 Jun 2024 18:08:04 +0800 Subject: [PATCH 24/38] docs(array): fixed https://github.com/wangdoc/es6-tutorial/issues/22 --- docs/array.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/array.md b/docs/array.md index d12d4a38e..e4ed02e8e 100644 --- a/docs/array.md +++ b/docs/array.md @@ -881,9 +881,7 @@ sentence.at(100) // undefined ## 实例方法:toReversed(),toSorted(),toSpliced(),with() -很多数组的传统方法会改变原数组,比如`push()`、`pop()`、`shift()`、`unshift()`等等。数组只要调用了这些方法,它的值就变了。现在有一个[提案](https://github.com/tc39/proposal-change-array-by-copy),允许对数组进行操作时,不改变原数组,而返回一个原数组的拷贝。 - -这样的方法一共有四个。 +很多数组的传统方法会改变原数组,比如`push()`、`pop()`、`shift()`、`unshift()`等等。数组只要调用了这些方法,它的值就变了。[ES2023](https://github.com/tc39/proposal-change-array-by-copy)引入了四个新方法,对数组进行操作时,不改变原数组,而返回一个原数组的拷贝。 - `Array.prototype.toReversed() -> Array` - `Array.prototype.toSorted(compareFn) -> Array` From 1a445eca49782ff86ade4aeafb300dfd02015112 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Fri, 19 Jul 2024 17:47:06 +0800 Subject: [PATCH 25/38] docs(generator): fixed typo --- docs/generator.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator.md b/docs/generator.md index 283b84484..f93604c0b 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -259,7 +259,7 @@ b.next(12) // { value:8, done:false } b.next(13) // { value:42, done:true } ``` -上面代码中,第二次运行`next`方法的时候不带参数,导致 y 的值等于`2 * undefined`(即`NaN`),除以 3 以后还是`NaN`,因此返回对象的`value`属性也等于`NaN`。第三次运行`Next`方法的时候不带参数,所以`z`等于`undefined`,返回对象的`value`属性等于`5 + NaN + undefined`,即`NaN`。 +上面代码中,第二次运行`next`方法的时候不带参数,导致 y 的值等于`2 * undefined`(即`NaN`),除以 3 以后还是`NaN`,因此返回对象的`value`属性也等于`NaN`。第三次运行`next`方法的时候不带参数,所以`z`等于`undefined`,返回对象的`value`属性等于`5 + NaN + undefined`,即`NaN`。 如果向`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`。 From f6e88af4bd0f5609d1c5bd405fd9750b3e3a5668 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 24 Jul 2024 20:57:35 +0800 Subject: [PATCH 26/38] docs(string-methods): add .toWellFormed() --- docs/string-methods.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/string-methods.md b/docs/string-methods.md index 2fc48b4c8..79520fc9a 100644 --- a/docs/string-methods.md +++ b/docs/string-methods.md @@ -450,3 +450,38 @@ str.at(-1) // "o" 如果参数位置超出了字符串范围,`at()`返回`undefined`。 该方法来自数组添加的`at()`方法,目前还是一个第三阶段的提案,可以参考《数组》一章的介绍。 + +## 实例方法:toWellFormed() + +ES2024 引入了新的字符串方法`toWellFormed()`,用来处理 Unicode 的代理字符对问题(surrogates)。 + +JavaScript 语言内部使用 UTF-16 格式,表示每个字符。UTF-16 只有16位,只能表示码点在`U+0000`到`U+FFFF`之间的 Unicode 字符。对于码点大于`U+FFFF`的 Unicode 字符(即码点大于16位的字符,`U+10000`到`U+10FFFF`),解决办法是使用代理字符对,即用两个 UTF-16 字符组合表示。 + +具体来说,UTF-16 规定,`U+D800`至`U+DFFF`是空字符段,专门留给代理字符对使用。只要遇到这个范围内的码点,就知道它是代理字符对,本身没有意义,必须两个字符结合在一起解读。其中,前一个字符的范围规定为`0xD800`到`0xDBFF`之间,后一个字符的范围规定为`0xDC00`到`0xDFFF`之间。举例来说,码点`U+1D306`对应的字符为`𝌆`,它写成 UTF-16 就是`0xD834 0xDF06`。 + +但是,字符串里面可能会出现单个代理字符对,即`U+D800`至`U+DFFF`里面的字符,它没有配对的另一个字符,无法进行解读,导致出现各种状况。 + +`.toWellFormed()`就是为了解决这个问题,不改变原始字符串,返回一个新的字符串,将原始字符串里面的单个代理字符对,都替换为`U+FFFD`,从而可以在任何正常处理字符串的函数里面使用。 + +```javascript +"ab\uD800".toWellFormed() // 'ab�' +``` + +上面示例中,`\uD800`是单个的代理字符对,单独使用时没有意义。`toWellFormed()`将这个字符转为`\uFFFD`。 + +再看下面的例子,`encodeURI()`遇到单个的代理字符对,会报错。 + +```javascript +const illFormed = "https://example.com/search?q=\uD800"; + +encodeURI(illFormed) // 报错 +``` + +`toWellFormed()`将其转换格式后,再使用`encodeURI()`就不会报错了。 + +```javascript +const illFormed = "https://example.com/search?q=\uD800"; + +encodeURI(illFormed.toWellFormed()) // 正确 +``` + From cc18cea57c3c96dc562ed5055252c1eb1a152611 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 24 Jul 2024 21:31:02 +0800 Subject: [PATCH 27/38] docs(regex): edit v flag --- docs/regex.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/regex.md b/docs/regex.md index 87c3410a0..02f2439ea 100644 --- a/docs/regex.md +++ b/docs/regex.md @@ -483,7 +483,7 @@ regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘ ## v 修饰符:Unicode 属性类的运算 -有时,需要向某个 Unicode 属性类添加或减少字符,即需要对属性类进行运算。现在有一个[提案](https://github.com/tc39/proposal-regexp-v-flag),增加了 Unicode 属性类的运算功能。 +有时,需要向某个 Unicode 属性类添加或减少字符,即需要对属性类进行运算。[ES2024](https://github.com/tc39/proposal-regexp-v-flag) 增加了 Unicode 属性类的运算功能。 它提供两种形式的运算,一种是差集运算(A 集合减去 B 集合),另一种是交集运算。 @@ -516,6 +516,22 @@ regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘ [\p{Emoji}--\p{ASCII}] ``` +看一个实际的例子,`0`属于十进制字符类。 + +```javascript +/[\p{Decimal_Number}]/u.test('0') // true +``` + +上面示例中,字符类是 Unicode 专用的,所以必须使用`u`修饰符。 + +如果把`0-9`从十进制字符类里面去掉,那么`0`就不属于这个类了。 + +```javascript +/[\p{Decimal_Number}--[0-9]]/v.test('0') // false +``` + +上面示例中,`v`修饰符只能用于 Unicode,所以可以省略`u`修饰符。 + ## 具名组匹配 ### 简介 From bdbcf3e520536eff4c58c2920318cc11f1a1c409 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 24 Jul 2024 21:54:13 +0800 Subject: [PATCH 28/38] docs(proposals): edit pipe operator --- docs/proposals.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/proposals.md b/docs/proposals.md index cfa19bc30..2626982b0 100644 --- a/docs/proposals.md +++ b/docs/proposals.md @@ -314,6 +314,18 @@ const userAge = userId |> await fetchUserById |> getAgeFromUser; const userAge = getAgeFromUser(await fetchUserById(userId)); ``` +管道运算符对多步骤的数据处理,非常有用。 + +```javascript +const numbers = [10, 20, 30, 40, 50]; + +const processedNumbers = numbers + |> (_ => _.map(n => n / 2)) // [5, 10, 15, 20, 25] + |> (_ => _.filter(n => n > 10)); // [15, 20, 25] +``` + +上面示例中,管道运算符可以清晰表达数据处理的每一步,增加代码的可读性。 + ## Math.signbit() JavaScript 内部使用64位浮点数(国际标准 IEEE 754)表示数值。IEEE 754 规定,64位浮点数的第一位是符号位,`0`表示正数,`1`表示负数。所以会有两种零,`+0`是符号位为`0`时的零,`-0`是符号位为`1`时的零。实际编程中,判断一个值是`+0`还是`-0`非常麻烦,因为它们是相等的。 From ff265f79826d9c5447eff0b17a682432386af077 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 25 Jul 2024 14:42:35 +0800 Subject: [PATCH 29/38] docs(set): edit set operator methods --- docs/set-map.md | 156 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 18 deletions(-) diff --git a/docs/set-map.md b/docs/set-map.md index c5fa699ee..4407477bd 100644 --- a/docs/set-map.md +++ b/docs/set-map.md @@ -21,7 +21,7 @@ for (let i of s) { 上面代码通过`add()`方法向 Set 结构加入成员,结果表明 Set 结构不会添加重复的值。 -`Set`函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。 +`Set()`函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。 ```javascript // 例一 @@ -88,6 +88,23 @@ set.size // 2 上面代码表示,由于两个空对象不相等,所以它们被视为两个值。 +`Array.from()`方法可以将 Set 结构转为数组。 + +```javascript +const items = new Set([1, 2, 3, 4, 5]); +const array = Array.from(items); +``` + +这就提供了去除数组重复成员的另一种方法。 + +```javascript +function dedupe(array) { + return Array.from(new Set(array)); +} + +dedupe([1, 1, 2, 3]) // [1, 2, 3] +``` + ### Set 实例的属性和方法 Set 结构的实例有以下属性。 @@ -142,23 +159,6 @@ if (properties.has(someName)) { } ``` -`Array.from()`方法可以将 Set 结构转为数组。 - -```javascript -const items = new Set([1, 2, 3, 4, 5]); -const array = Array.from(items); -``` - -这就提供了去除数组重复成员的另一种方法。 - -```javascript -function dedupe(array) { - return Array.from(new Set(array)); -} - -dedupe([1, 1, 2, 3]) // [1, 2, 3] -``` - ### 遍历操作 Set 结构的实例有四个遍历方法,可以用于遍历成员。 @@ -302,6 +302,122 @@ set = new Set(Array.from(set, val => val * 2)); 上面代码提供了两种方法,直接在遍历操作中改变原来的 Set 结构。 +### 集合运算 + +[ES2025](https://github.com/tc39/proposal-set-methods) 为 Set 结构添加了以下集合运算方法。 + +- Set.prototype.intersection(other):交集 +- Set.prototype.union(other):并集 +- Set.prototype.difference(other):差集 +- Set.prototype.symmetricDifference(other):对称差集 +- Set.prototype.isSubsetOf(other):判断是否为子集 +- Set.prototype.isSupersetOf(other):判断是否为超集 +- Set.prototype.isDisjointFrom(other):判断是否不相交 + +以上方法的参数都必须是 Set 结构,或者是一个类似于 Set 的结构(拥有`size`属性,以及`keys()`和`has()`方法。 + +`.union()`是并集运算,返回包含两个集合中存在的所有成员的集合。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const backEnd = new Set(["Python", "Java", "JavaScript"]); + +const all = frontEnd.union(backEnd); +// Set {"JavaScript", "HTML", "CSS", "Python", "Java"} +``` + +`.intersection()`是交集运算,返回同时包含在两个集合中的成员的集合。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const backEnd = new Set(["Python", "Java", "JavaScript"]); + +const frontAndBackEnd = frontEnd.intersection(backEnd); +// Set {"JavaScript"} +``` + +`.difference()`是差集运算,返回第一个集合中存在但第二个集合中不存在的所有成员的集合。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const backEnd = new Set(["Python", "Java", "JavaScript"]); + +const onlyFrontEnd = frontEnd.difference(backEnd); +// Set {"HTML", "CSS"} + +const onlyBackEnd = backEnd.difference(frontEnd); +// Set {"Python", "Java"} +``` + +`.symmetryDifference()`是对称差集,返回两个集合的所有独一无二成员的集合,即去除了重复的成员。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const backEnd = new Set(["Python", "Java", "JavaScript"]); + +const onlyFrontEnd = frontEnd.symmetricDifference(backEnd); +// Set {"HTML", "CSS", "Python", "Java"} + +const onlyBackEnd = backEnd.symmetricDifference(frontEnd); +// Set {"Python", "Java", "HTML", "CSS"} +``` + +注意,返回结果中的成员顺序,由添加到集合的顺序决定。 + +`.isSubsetOf()`返回一个布尔值,判断第一个集合是否为第二个集合的子集,即第一个集合的所有成员都是第二个集合的成员。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const declarative = new Set(["HTML", "CSS"]); + +declarative.isSubsetOf(frontEnd); +// true + +frontEndLanguages.isSubsetOf(declarativeLanguages); +// false +``` + +任何集合都是自身的子集。 + +```javascript +frontEnd.isSubsetOf(frontEnd); +// true +``` + +`isSupersetOf()`返回一个布尔值,表示第一个集合是否为第二个集合的超集,即第二个集合的所有成员都是第一个集合的成员。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const declarative = new Set(["HTML", "CSS"]); + +declarative.isSupersetOf(frontEnd); +// false + +frontEnd.isSupersetOf(declarative); +// true +``` + +任何集合都是自身的超集。 + +```javascript +frontEnd.isSupersetOf(frontEnd); +// true +``` + +`.isDisjointFrom()`判断两个集合是否不相交,即没有共同成员。 + +```javascript +const frontEnd = new Set(["JavaScript", "HTML", "CSS"]); +const interpreted = new Set(["JavaScript", "Ruby", "Python"]); +const compiled = new Set(["Java", "C++", "TypeScript"]); + +interpreted.isDisjointFrom(compiled); +// true + +frontEnd.isDisjointFrom(interpreted); +// false +``` + ## WeakSet ### 含义 @@ -1283,3 +1399,7 @@ class Thingy { 由于无法知道清理器何时会执行,所以最好避免使用它。另外,如果浏览器窗口关闭或者进程意外退出,清理器则不会运行。 +## 参考链接 + +- [Union, intersection, difference, and more are coming to JavaScript Sets](https://www.sonarsource.com/blog/union-intersection-difference-javascript-sets/) + From 3b89ca42e86442c412d2c95bbcce490717eacd2c Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 25 Jul 2024 16:51:38 +0800 Subject: [PATCH 30/38] docs(temporal): add temporal API --- docs/temporal.md | 184 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 docs/temporal.md diff --git a/docs/temporal.md b/docs/temporal.md new file mode 100644 index 000000000..b0a4be452 --- /dev/null +++ b/docs/temporal.md @@ -0,0 +1,184 @@ +# Temporal API + +Temporal 是一个表示日期时间的全新 API,对目前的 Date API 的诸多问题进行修正。 + +## Temporal.Now + +`Temporal.Now`表示当前系统的准确时间。 + +- Temporal.Now.instant()- 获取当前系统准确时间 +- Temporal.Now.timeZoneId()- 获取当前系统时区 +- Temporal.Now.zonedDateTimeISO()- 获取系统时区和 ISO-8601 日历中的当前日期和挂钟时间 +- Temporal.Now.plainDateISO()- 获取系统时区和 ISO-8601 日历中的当前日期 +- Temporal.Now.plainTimeISO()- 获取系统时区和 ISO-8601 日历中的当前挂钟时间 +- Temporal.Now.plainDateTimeISO()- 与上面相同,但返回 ISO-8601 日历中的日期时间 + +```javascript +// 返回 UTC 的当前时间 +Temporal.Now.instant().toString() + +// 返回某个时区的当前日期时间 +Temporal.Now.zonedDateTimeISO('Asia/Shanghai').toString() + +// 返回 ISO 格式当前日期时间 +Temporal.Now.plainDateTimeISO().toString() + +// 返回 ISO 格式的当前时间,不含日期 +Temporal.Now.plainTimeISO().toString() +``` + +下面的例子是获取指定时区的当前时间。 + +```javascript +const now = Temporal.Now.zonedDateTimeISO('America/New_York'); +console.log(now.toString()); +``` + +## Temporal.Instant + +`Temporal.Instant`表示某个固定的时间。 + +```javascript +const instant = Temporal.Instant.from('1969-07-20T20:17Z'); +instant.toString(); // => '1969-07-20T20:17:00Z' +instant.epochMilliseconds; // => -14182980000 +``` + +## Temporal.ZonedDateTime + +`Temporal.ZonedDateTime`表示某个时区的时间。 + +```javascript +const zonedDateTime = Temporal.ZonedDateTime.from({ + timeZone: 'America/Los_Angeles', + year: 1995, + month: 12, + day: 7, + hour: 3, + minute: 24, + second: 30, + millisecond: 0, + microsecond: 3, + nanosecond: 500 +}); // => 1995-12-07T03:24:30.0000035-08:00[America/Los_Angeles] +``` + +## Temporal.PlainDate + +`Temporal.PlainDate`表示与时区无关的日期。 + +```javascript +const date = Temporal.PlainDate.from({ year: 2006, month: 8, day: 24 }); // => 2006-08-24 +date.year; // => 2006 +date.inLeapYear; // => false +date.toString(); // => '2006-08-24' +``` + +下面的例子是计算某个日期以后的时间。 + +```javascript +const date = Temporal.PlainDate.from('2024-01-01'); +const newDate = date.add({ days: 10 }); +console.log(newDate.toString()); // Outputs '2024-01-11' +``` + +## Temporal.PlainTime + +`Temporal.PlainTime`表示与时区无关的某个时点。 + +```javascript +const time = Temporal.PlainTime.from({ + hour: 19, + minute: 39, + second: 9, + millisecond: 68, + microsecond: 346, + nanosecond: 205 +}); // => 19:39:09.068346205time.second; // => 9 +time.toString(); // => '19:39:09.068346205' +``` + +## Temporal.PlainDateTime + +`Temporal.PlainDateTime`表示时区无关的日期时间。 + +```javascript +const dateTime = Temporal.PlainDateTime.from({ + year: 1995, + month: 12, + day: 7, + hour: 15 +}); // => 1995-12-07T15:00:00 +const dateTime1 = dateTime.with({ + minute: 17, + second: 19 +}); // => 1995-12-07T15:17:19 +``` + +## Temporal.PlainYearMonth + +`Temporal.PlainYearMonth`表示不含日期的年月。 + +```javascript +const yearMonth = Temporal.PlainYearMonth.from({ year: 2020, month: 10 }); // => 2020-10 +yearMonth.daysInMonth; // => 31 +yearMonth.daysInYear; // => 366 +``` + +## Temporal.PlainMonthDay + +`Temporal.PlainMonthDay`表示没有年份的月和日。 + +下面是计算生日的例子。 + +```javascript +const birthday = Temporal.PlainMonthDay.from("12-15"); +// 或者写成 +// const birthday = Temporal.PlainMonthDay.from({ month: 12, day: 15 }) + +const birthdayIn2030 = birthday.toPlainDate({ year: 2030 }); + +birthdayIn2030.toString() // 2030-12-15 +birthdayIn2030.dayOfWeek // 7 +``` + +## Temporal.Duration + +`Temporal.Duration`表示时长。 + +```javascript +const duration = Temporal.Duration.from({ + hours: 130, + minutes: 20 +}); + +duration.total({ unit: 'second' }); // => 469200 +``` + +## Temporal.TimeZone + +`Temporal.TimeZone`表示某个时区。 + +```javascript +const timeZone = Temporal.TimeZone.from('Africa/Cairo'); +timeZone.getInstantFor('2000-01-01T00:00'); // => 1999-12-31T22:00:00Z +timeZone.getPlainDateTimeFor('2000-01-01T00:00Z'); // => 2000-01-01T02:00:00 +timeZone.getPreviousTransition(Temporal.Now.instant()); // => 2014-09-25T21:00:00Z +timeZone.getNextTransition(Temporal.Now.instant()); // => null +``` + +## Temporal.Calendar + +`Temporal.Calendar`表示某个日历系统。 + +```javascript +const cal = Temporal.Calendar.from('iso8601'); +const date = cal.dateFromFields({ year: 1999, month: 12, day: 31 }, {}); +date.monthsInYear; // => 12 +date.daysInYear; // => 365 +``` + +## 参考链接 + +- [Temporal documentation](https://tc39.es/proposal-temporal/docs/) + From 43e44201a8688ab3c0c87f614e7d3c6b19f2d922 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Thu, 25 Jul 2024 17:06:22 +0800 Subject: [PATCH 31/38] docs(module): edit import.meta --- docs/module.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/module.md b/docs/module.md index 5d68da67a..207c38306 100644 --- a/docs/module.md +++ b/docs/module.md @@ -855,3 +855,14 @@ import.meta.scriptElement.dataset.foo // "abc" ``` +**(3)其他** + +Deno 现在还支持`import.meta.filename`和`import.meta.dirname`属性,对应 CommonJS 模块系统的`__filename`和`__dirname`属性。 + +- `import.meta.filename`:当前模块文件的绝对路径。 +- `import.meta.dirname`:当前模块文件的目录的绝对路径。 + +这两个属性都提供当前平台的正确的路径分隔符,比如 Linux 系统返回`/dev/my_module.ts`,Windows 系统返回`C:\dev\my_module.ts`。 + +本地模块可以使用这两个属性,远程模块也可以使用。 + From a434080ef30878f6425585c536501b9aade804ce Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sun, 25 Aug 2024 19:11:48 +0800 Subject: [PATCH 32/38] docs(temporal): edit ZonedTimezome --- docs/temporal.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/docs/temporal.md b/docs/temporal.md index b0a4be452..4ce18ad20 100644 --- a/docs/temporal.md +++ b/docs/temporal.md @@ -46,7 +46,17 @@ instant.epochMilliseconds; // => -14182980000 ## Temporal.ZonedDateTime -`Temporal.ZonedDateTime`表示某个时区的时间。 +`Temporal.ZonedDateTime`表示某个时区的时间。它会在 ISO8601 的标准格式后面,添加时区后缀和历法后缀。 + +```javascript +2020-08-05T20:06:13+09:00[Asia/Tokyo][u-ca=japanese] +``` + +上面示例中,`2020-08-05T20:06:13+09:00`是 ISO8601 标准格式,`[Asia/Tokyo]`是时区后缀,`[u-ca=japanese]`是历法后缀,表示采用日本历法。 + +默认的历法是 ISO8601 规定的公历,可以省略不写。 + +下面是使用`Temporal.ZonedDateTime.from()`新建 ZonedDateTime 实例对象的例子。 ```javascript const zonedDateTime = Temporal.ZonedDateTime.from({ @@ -63,6 +73,65 @@ const zonedDateTime = Temporal.ZonedDateTime.from({ }); // => 1995-12-07T03:24:30.0000035-08:00[America/Los_Angeles] ``` +下面是使用`Temporal.ZonedDateTime.compare()`比较两个 ZonedDateTime 实例对象的例子。 + +```javascript +const one = Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]'); +const two = Temporal.ZonedDateTime.from('2020-11-01T01:15-08:00[America/Los_Angeles]'); + +Temporal.ZonedDateTime.compare(one, two); +// -1 +``` + +上面示例中,`Temporal.ZonedDateTime.compare()`返回`-1`,表示第一个时间小于(即早于)第二个时间。如果返回`1`,表示第一个时间大于第二个时间;返回`0`,表示两个时间相等。 + +ZonedDateTime 实例对象有以下属性。 + +- hoursInDay:指定时区的某一天一共有多少个小时,主要用来处理夏令时。 + +```javascript +Temporal.ZonedDateTime.from('2020-01-01T12:00-08:00[America/Los_Angeles]').hoursInDay; +// 24 +Temporal.ZonedDateTime.from('2020-03-08T12:00-07:00[America/Los_Angeles]').hoursInDay; +// 23 +Temporal.ZonedDateTime.from('2020-11-01T12:00-08:00[America/Los_Angeles]').hoursInDay; +// 25 +``` + +- daysInYear +- inLeapYear + +ZonedDateTime 实例对象有以下方法。 + +- .withTimeZone():切换时区。 + +```javascript +zdt = Temporal.ZonedDateTime.from('1995-12-07T03:24:30+09:00[Asia/Tokyo]'); +zdt.toString(); // => '1995-12-07T03:24:30+09:00[Asia/Tokyo]' +zdt.withTimeZone('Africa/Accra').toString(); // => '1995-12-06T18:24:30+00:00[Africa/Accra]' +``` + +- add():增加时间。 + +```javascript +zdt = Temporal.ZonedDateTime.from('2020-03-08T00:00-08:00[America/Los_Angeles]'); + +// 增加一天 +laterDay = zdt.add({ days: 1 }); +// 2020-03-09T00:00:00-07:00[America/Los_Angeles] +// 注意:时区改变了,表示洛杉矶这个日期处于夏令时,比正常情况早一个小时 + +laterDay.since(zdt, { largestUnit: 'hour' }).hours; +// 23 +// 当天只有23小时 + +laterHours = zdt.add({ hours: 24 }); +// 2020-03-09T01:00:00-07:00[America/Los_Angeles] +laterHours.since(zdt, { largestUnit: 'hour' }).hours; // 24 +``` + +- .until():计算两个时间之间的差异。 + ## Temporal.PlainDate `Temporal.PlainDate`表示与时区无关的日期。 @@ -181,4 +250,5 @@ date.daysInYear; // => 365 ## 参考链接 - [Temporal documentation](https://tc39.es/proposal-temporal/docs/) +- [JS Dates Are About to Be Fixed](https://docs.timetime.in/blog/js-dates-finally-fixed/) From b7b6c912957ce9809ead933cad9999c1d01ba031 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 24 Sep 2024 22:13:39 +0800 Subject: [PATCH 33/38] docs(number): fixed space style --- docs/number.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/number.md b/docs/number.md index e9904c567..1b3cfbbf0 100644 --- a/docs/number.md +++ b/docs/number.md @@ -820,7 +820,7 @@ for (let i = 1; i <= 70; i++) { console.log(p); // 1.197857166996989e+100 ``` -现在支持大整数了,就可以算了,浏览器的开发者工具运行下面代码,就OK。 +现在支持大整数了,就可以算了,浏览器的开发者工具运行下面代码,就 OK。 ```javascript let p = 1n; From a100783a99259048fbe465638ad1085ffd4631fc Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 25 Dec 2024 10:03:33 +0800 Subject: [PATCH 34/38] docs(object): fixed typo --- docs/object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/object.md b/docs/object.md index cd817ec1e..8abd76c23 100644 --- a/docs/object.md +++ b/docs/object.md @@ -783,7 +783,7 @@ actual.cause; // 'Error cause' 上面示例中,生成 Error 实例时,使用描述对象给出`cause`属性,写入报错的原因。然后,就可以从实例对象上读取这个属性。 -`casue`属性可以放置任意内容,不必一定是字符串。 +`cause`属性可以放置任意内容,不必一定是字符串。 ```javascript try { From 4c80184abe6d7cea9d1b79a5e837d7eca9dd6b25 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 31 Dec 2024 16:24:06 +0800 Subject: [PATCH 35/38] docs(string-methonds): fixed typo --- docs/string-methods.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/string-methods.md b/docs/string-methods.md index 79520fc9a..1d3e63a8e 100644 --- a/docs/string-methods.md +++ b/docs/string-methods.md @@ -421,7 +421,7 @@ String.prototype.replaceAll(searchValue, replacement) 上面例子中,`replaceAll()`的第二个参数是一个函数,该函数的返回值会替换掉所有`b`的匹配。 -这个替换函数可以接受多个参数。第一个参数是捕捉到的匹配内容,第二个参数捕捉到是组匹配(有多少个组匹配,就有多少个对应的参数)。此外,最后还可以添加两个参数,倒数第二个参数是捕捉到的内容在整个字符串中的位置,最后一个参数是原字符串。 +这个替换函数可以接受多个参数。第一个参数是捕捉到的匹配内容,第二个参数是捕捉到的组匹配(有多少个组匹配,就有多少个对应的参数)。此外,最后还可以添加两个参数,倒数第二个参数是捕捉到的内容在整个字符串中的位置,最后一个参数是原字符串。 ```javascript const str = '123abc456'; From 42cd9e36d145bc6ca4a4093238bb9120ca358a36 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 25 Jan 2025 18:55:49 +0800 Subject: [PATCH 36/38] docs(temporal): add text --- docs/temporal.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/docs/temporal.md b/docs/temporal.md index 4ce18ad20..e11341192 100644 --- a/docs/temporal.md +++ b/docs/temporal.md @@ -2,6 +2,18 @@ Temporal 是一个表示日期时间的全新 API,对目前的 Date API 的诸多问题进行修正。 +它有几个核心概念。 + +- 当前时间:表示此时此刻的时间,位于 Temporal.now 对象。 +- 时点(instant),表示历史上某个唯一时间,其中 Temporal.Instant 对象表示时间戳,Temporal.ZonedDateTime 表示带有时区的日期时间。 +- 时钟时间(wall-clock times),表示本地时间,包含以下几个对象,不涉及时区。 + - Temporal.PlainDateTime:完整的日期和时间。 + - Temporal.PlainDate:仅限于日期。 + - Temporal.PlainYearMonth:仅限于年月。 + - Temporal.PlainMonthDay:仅限于月和日。 + - Temporal.PlainTime:不包含日期的时间。 +- 持续时间(durations),表示两个时间点之间的差异,位于 Temporal.Duration 对象。 + ## Temporal.Now `Temporal.Now`表示当前系统的准确时间。 @@ -17,6 +29,12 @@ Temporal 是一个表示日期时间的全新 API,对目前的 Date API 的诸 // 返回 UTC 的当前时间 Temporal.Now.instant().toString() +// 系统时区的当前时间 +Temporal.Now.plainDateTimeISO() // 2025-01-22T11:46:36.144 + +// 当前时间对应 America/New_York 时区的时间 +Temporal.Now.plainDateTimeISO("America/New_York") // 2025-01-22T05:47:02.555 + // 返回某个时区的当前日期时间 Temporal.Now.zonedDateTimeISO('Asia/Shanghai').toString() @@ -34,14 +52,25 @@ const now = Temporal.Now.zonedDateTimeISO('America/New_York'); console.log(now.toString()); ``` +下面的例子是获取当前时间对应的农历年。 + +```javascript +const currentYear = Temporal.Now.plainDateISO().withCalendar("chinese").year; +``` + ## Temporal.Instant -`Temporal.Instant`表示某个固定的时间。 +`Temporal.Instant`表示某个固定的时点。 ```javascript const instant = Temporal.Instant.from('1969-07-20T20:17Z'); instant.toString(); // => '1969-07-20T20:17:00Z' instant.epochMilliseconds; // => -14182980000 + +// 某个 Unix 时间戳对应的时点 +const launch = Temporal.Instant.fromEpochMilliseconds(1851222399924); +const now = Temporal.Now.instant(); +const duration = now.until(launch, { smallestUnit: "hour" }); ``` ## Temporal.ZonedDateTime @@ -211,6 +240,27 @@ birthdayIn2030.toString() // 2030-12-15 birthdayIn2030.dayOfWeek // 7 ``` +下面是农历一月一日(大年初一)的例子。 + +```javascript +const chineseNewYear = Temporal.PlainMonthDay.from({ + monthCode: "M01", + day: 1, + calendar: "chinese", +}); + +const currentYear = Temporal.Now.plainDateISO().withCalendar("chinese").year; + +// 获取下一个春节 +let nextCNY = chineseNewYear.toPlainDate({ year: currentYear }); +// 如果 nextCNY 早于当前时间,则向后移动一年 +if (Temporal.PlainDate.compare(nextCNY, Temporal.Now.plainDateISO()) <= 0) { + nextCNY = nextCNY.add({ years: 1 }); +} + +nextCNY.withCalendar("iso8601").toLocaleString() // 1/29/2025 +``` + ## Temporal.Duration `Temporal.Duration`表示时长。 @@ -247,8 +297,26 @@ date.monthsInYear; // => 12 date.daysInYear; // => 365 ``` +## Temporal.Duration + +Temporal.Duration 表示一个持续的时间对象。 + +```javascript +const durations = [ + Temporal.Duration.from({ hours: 1 }), + Temporal.Duration.from({ hours: 2 }), + Temporal.Duration.from({ hours: 1, minutes: 30 }), + Temporal.Duration.from({ hours: 1, minutes: 45 }), +]; + +durations.sort(Temporal.Duration.compare); +console.log(durations.map((d) => d.toString())); +// [ 'PT1H', 'PT1H30M', 'PT1H45M', 'PT2H' ] +```` + ## 参考链接 - [Temporal documentation](https://tc39.es/proposal-temporal/docs/) - [JS Dates Are About to Be Fixed](https://docs.timetime.in/blog/js-dates-finally-fixed/) +- [JavaScript Temporal is coming](https://developer.mozilla.org/en-US/blog/javascript-temporal-is-coming/) From cbbf9ac29642351144759ea980e2cbe3c9f02fc2 Mon Sep 17 00:00:00 2001 From: zihua <63008995+zihua-1022@users.noreply.github.com> Date: Sat, 22 Feb 2025 19:50:26 +0800 Subject: [PATCH 37/38] Update promise.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit console.log的输出和展示结果不一致 --- docs/promise.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/promise.md b/docs/promise.md index ee6a7aab8..758bb2edd 100644 --- a/docs/promise.md +++ b/docs/promise.md @@ -79,7 +79,7 @@ let promise = new Promise(function(resolve, reject) { }); promise.then(function() { - console.log('resolved.'); + console.log('resolved'); }); console.log('Hi!'); From 17d58f73020a85288f110da44f9f5ad090373e9d Mon Sep 17 00:00:00 2001 From: Chuck Lau Date: Sun, 27 Apr 2025 13:52:02 +0800 Subject: [PATCH 38/38] docs: fix typo in reference.md --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index bb3f87c71..359d045b1 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -184,7 +184,7 @@ ## 异步操作和 Async 函数 -- Luke Hoban, [Async Functions for ECMAScript](https://github.com/lukehoban/ecmascript-asyncawait): Async 函数的设计思想,与 Promise、Gernerator 函数的关系 +- Luke Hoban, [Async Functions for ECMAScript](https://github.com/lukehoban/ecmascript-asyncawait): Async 函数的设计思想,与 Promise、Generator 函数的关系 - Jafar Husain, [Asynchronous Generators for ES7](https://github.com/jhusain/asyncgenerator): Async 函数的深入讨论 - Nolan Lawson, [Taming the asynchronous beast with ES7](http://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html): async 函数通俗的实例讲解 - Jafar Husain, [Async Generators](https://docs.google.com/file/d/0B4PVbLpUIdzoMDR5dWstRllXblU/view?sle=true): 对 async 与 Generator 混合使用的一些讨论