1
- # 目录概要
1
+ # ** 目录概要**
2
2
3
3
> 第 1 章,介绍 JavaScript 的起源:从哪里来,如何发展,以及现今的状况。这一章会谈到 JavaScript与 ECMAScript 的关系、 DOM、 BOM,以及 Ecma 和 W3C 相关的标准。
4
4
> 第 2 章,了解 JavaScript 如何与 HTML 结合来创建动态网页,主要介绍在网页中嵌入 JavaScript 的不同方式,还有 JavaScript 的内容类型及其与` <script> ` 元素的关系。
@@ -2525,9 +2525,9 @@ Date 类型将日期保存为自协调世界时( UTC, Universal Time Coordin
2525
2525
2526
2526
Date 类型重写了 `toLocaleString()、 toString() 和 valueOf()` 方法。但与其他类型不同,重写后这些方法的返回值不一样。
2527
2527
2528
- - Date 类型的 toLocaleString() 方法返回与浏览器运行的本地环境一致的日期和时间。这通常意味着格式中包含针对时间的 AM(上午)或 PM(下午),但不包含时区信息(具体格式可能因浏览器而不同)。
2528
+ - Date 类型的 **` toLocaleString()`** 方法返回与浏览器运行的本地环境一致的日期和时间。这通常意味着格式中包含针对时间的 AM(上午)或 PM(下午),但不包含时区信息(具体格式可能因浏览器而不同)。
2529
2529
2530
- - toString()方法通常返回带时区信息的日期和时间,而时间也是以 24 小时制( 0~23)表示的。
2530
+ - **` toString()`** 方法通常返回带时区信息的日期和时间,而时间也是以 24 小时制( 0~23)表示的。
2531
2531
2532
2532
- 下面给出了 toLocaleString() 和 toString() 返回的2019 年 2 月 1 日零点的示例(地区为"en-US"的 PST,即 Pacific Standard Time,太平洋标准时间):
2533
2533
@@ -2550,12 +2550,12 @@ Date 类型重写了 `toLocaleString()、 toString() 和 valueOf()` 方法。但
2550
2550
### 5.1.2 日期格式化方法
2551
2551
2552
2552
- Date 类型有几个专门用于格式化日期的方法,它们都会返回字符串:
2553
- - toDateString() 显示日期中的周几、月、日、年(格式特定于实现);
2554
- - toTimeString() 显示日期中的时、分、秒和时区(格式特定于实现);
2555
- - toLocaleDateString() 显示日期中的周几、月、日、年(格式特定于实现和地区);
2556
- - toLocaleTimeString() 显示日期中的时、分、秒(格式特定于实现和地区);
2557
- - toUTCString() 显示完整的 UTC 日期(格式特定于实现)。
2558
- - 这些方法的输出与 toLocaleString() 和 toString() 一样,会因浏览器而异。因此不能用于在用户界面上一致地显示日期 。
2553
+ - **` toDateString()`** 显示日期中的周几、月、日、年(格式特定于实现);
2554
+ - **` toTimeString()`** 显示日期中的时、分、秒和时区(格式特定于实现);
2555
+ - **` toLocaleDateString()`** 显示日期中的周几、月、日、年(格式特定于实现和地区);
2556
+ - **` toLocaleTimeString()`** 显示日期中的时、分、秒(格式特定于实现和地区);
2557
+ - **` toUTCString()`** 显示完整的 UTC 日期(格式特定于实现)。
2558
+ - 这些方法的输出与 toLocaleString() 和 toString() 一样,会因浏览器而异。因此**不能用于在用户界面上一致地显示日期** 。
2559
2559
2560
2560
### 5.1.3 日期/时间组件方法
2561
2561
@@ -4787,17 +4787,244 @@ Map 是一种新的集合类型,为这门语言带来了真正的键/值存储
4787
4787
4788
4788
## 6.5 WeakMap
4789
4789
4790
- ECMAScript 6 新增的“弱映射”( WeakMap)是一种新的集合类型,为这门语言带来了增强的键/值对存储机制。
4790
+ ECMAScript 6 新增的** “弱映射”( WeakMap)** 是一种新的集合类型,为这门语言带来了增强的键/值对存储机制。
4791
4791
4792
4792
WeakMap 是 Map 的“兄弟”类型,其 API 也是 Map 的子集。
4793
4793
4794
- WeakMap 中的“weak”(弱),描述的是 JavaScript 垃圾回收程序对待“弱映射”中键的方式。
4794
+ WeakMap 中的 “weak”(弱),描述的是 JavaScript ** 垃圾回收程序对待“弱映射”中键的方式** 。
4795
4795
4796
4796
### 6.5.1 基本 API
4797
+
4798
+ - ` const wm = new WeakMap (); `
4799
+
4800
+ - 弱映射中的**键**只能是 **Object 或者继承自 Object 的类型**,尝试使用非对象设置键会抛出TypeError。值的类型没有限制。
4801
+
4802
+ - 如果想在初始化时填充弱映射,则构造函数可以接收一个可迭代对象,其中需要包含键/值对数组。
4803
+
4804
+ - 可迭代对象中的每个键/值都会按照迭代顺序插入新实例中。
4805
+
4806
+ ` ` ` javascript
4807
+ const key1 = {
4808
+ id: 1
4809
+ },
4810
+ key2 = {
4811
+ id: 2
4812
+ },
4813
+ key3 = {
4814
+ id: 3
4815
+ };
4816
+
4817
+ // 使用嵌套数组初始化弱映射
4818
+ const wm1 = new WeakMap ([
4819
+ [key1, " val1" ],
4820
+ [key2, " val2" ],
4821
+ [key3, " val3" ]
4822
+ ]);
4823
+ alert (wm1 .get (key1)); // val1
4824
+ alert (wm1 .get (key2)); // val2
4825
+ alert (wm1 .get (key3)); // val3
4826
+
4827
+ // 初始化是全有或全无的操作
4828
+ // 只要有一个键无效就会抛出错误,导致整个初始化失败
4829
+ const wm2 = new WeakMap ([
4830
+ [key1, " val1" ],
4831
+ [" BADKEY" , " val2" ],
4832
+ [key3, " val3" ]
4833
+ ]);
4834
+ // TypeError: Invalid value used as WeakMap key
4835
+ typeof wm2;
4836
+
4837
+ // ReferenceError: wm2 is not defined
4838
+ // 原始值可以先包装成对象再用作键
4839
+ const stringKey = new String (" key1" );
4840
+ const wm3 = new WeakMap ([
4841
+ stringKey, " val1"
4842
+ ]);
4843
+ alert (wm3 .get (stringKey)); // "val1"
4844
+ ` ` `
4845
+
4846
+ - 初始化之后可以使用 set() 再添加键/值对,可以使用 get() 和 has() 查询, 还可以使用 delete() 删除:
4847
+
4848
+ ` ` ` javascript
4849
+ const wm = new WeakMap ();
4850
+
4851
+ const key1 = {
4852
+ id: 1
4853
+ },
4854
+ key2 = {
4855
+ id: 2
4856
+ };
4857
+ alert (wm .has (key1)); // false
4858
+ alert (wm .get (key1)); // undefined
4859
+
4860
+ // set()方法返回弱映射实例,因此可以把多个操作连缀起来,包括初始化声明:
4861
+ wm .set (key1, " Matt" )
4862
+ .set (key2, " Frisbie" );
4863
+ alert (wm .has (key1)); // true
4864
+ alert (wm .get (key1)); // Matt
4865
+
4866
+ wm .delete (key1); // 只删除这一个键/值对
4867
+ alert (wm .has (key1)); // false
4868
+ alert (wm .has (key2)); // true
4869
+ ` ` `
4870
+
4871
+
4872
+
4797
4873
### 6.5.2 弱键
4874
+
4875
+ WeakMap 中“weak”表示弱映射的键是“弱弱地拿着”的。意思就是,这些键不属于正式的引用,不会阻止垃圾回收。
4876
+
4877
+ 但要注意的是,弱映射中值的引用可不是“弱弱地拿着”的。
4878
+
4879
+ **只要键存在,键/值对就会存在于映射中,并被当作对值的引用,因此就不会被当作垃圾回收**。
4880
+
4881
+ ` ` ` javascript
4882
+ const wm = new WeakMap ();
4883
+ wm .set ({}, " val" );
4884
+ ` ` `
4885
+
4886
+ - ` set ()` 方法初始化了一个新对象并将它用作一个字符串的键。因为没有指向这个对象的其他引用,所以当这行代码执行完成后,这个对象键就会被当作垃圾回收。然后,这个键/值对就从弱映射中消失了,使其成为一个空映射。在这个例子中,因为值也没有被引用,所以这对键/值被破坏以后,值本身也会成为垃圾回收的目标。
4887
+
4888
+ ` ` ` javascript
4889
+ const wm = new WeakMap ();
4890
+ const container = {
4891
+ key: {}
4892
+ };
4893
+ wm .set (container .key , " val" );
4894
+
4895
+ function removeReference () {
4896
+ container .key = null ;
4897
+ }
4898
+ ` ` `
4899
+
4900
+ 这一次, container 对象维护着一个对弱映射键的引用,因此这个对象键不会成为垃圾回收的目标。不过,如果调用了 ` removeReference ()` ,就会摧毁键对象的最后一个引用,垃圾回收程序就可以把这个键/值对清理掉。
4901
+
4902
+
4903
+
4798
4904
### 6.5.3 不可迭代键
4905
+
4906
+ - 因为 WeakMap 中的键/值对任何时候都可能被销毁,所以没必要提供迭代其键/值对的能力。
4907
+ - 当然,也用不着像 clear()这样一次性销毁所有键/值的方法。 WeakMap 确实没有这个方法。
4908
+ - 因为不可能迭代,所以也不可能在不知道对象引用的情况下从弱映射中取得值。即便代码可以访问 WeakMap 实例,也没办法看到其中的内容。
4909
+ - WeakMap 实例之所以限制只能用对象作为键,是为了保证只有通过键对象的引用才能取得值。
4910
+ - 如果允许原始值,那就没办法区分初始化时使用的字符串字面量和初始化之后使用的一个相等的字符串了。
4911
+
4912
+
4913
+
4799
4914
### 6.5.4 使用弱映射
4915
+
4916
+ 1. **私有变量 **
4917
+
4918
+ - 弱映射造就了在 JavaScript 中实现真正私有变量的一种新方式。
4919
+ - 私有变量会存储在弱映射中,以对象实例为键,以私有成员的字典为值。
4920
+
4921
+ ` ` ` javascript
4922
+ const wm = new WeakMap ();
4923
+
4924
+ class User {
4925
+ constructor (id ) {
4926
+ this .idProperty = Symbol (' id' );
4927
+ this .setId (id);
4928
+ }
4929
+ setPrivate (property , value ) {
4930
+ const privateMembers = wm .get (this ) || {};
4931
+ privateMembers[property] = value;
4932
+ wm .set (this , privateMembers);
4933
+ }
4934
+ getPrivate (property ) {
4935
+ return wm .get (this )[property];
4936
+ }
4937
+ setId (id ) {
4938
+ this .setPrivate (this .idProperty , id);
4939
+ }
4940
+ getId () {
4941
+ return this .getPrivate (this .idProperty );
4942
+ }
4943
+ }
4944
+
4945
+ const user = new User (123 );
4946
+ alert (user .getId ()); // 123
4947
+ user .setId (456 );
4948
+ alert (user .getId ()); // 456
4949
+
4950
+ // 并不是真正私有的
4951
+ alert (wm .get (user)[user .idProperty ]); // 456
4952
+ ` ` `
4953
+
4954
+ - 慧眼独具的读者会发现,对于上面的实现,外部代码只需要拿到对象实例的引用和弱映射,就可以取得“私有”变量了。为了避免这种访问,可以用一个闭包把 WeakMap 包装起来,这样就可以把弱映射与外界完全隔离开了:
4955
+
4956
+ ` ` ` javascript
4957
+ const User = (() => {
4958
+ const wm = new WeakMap ();
4959
+ class User {
4960
+ constructor (id ) {
4961
+ this .idProperty = Symbol (' id' );
4962
+ this .setId (id);
4963
+ }
4964
+ setPrivate (property , value ) {
4965
+ const privateMembers = wm .get (this ) || {};
4966
+ privateMembers[property] = value;
4967
+ wm .set (this , privateMembers);
4968
+ }
4969
+ getPrivate (property ) {
4970
+ return wm .get (this )[property];
4971
+ }
4972
+ setId (id ) {
4973
+ this .setPrivate (this .idProperty , id);
4974
+ }
4975
+ getId (id ) {
4976
+ return this .getPrivate (this .idProperty );
4977
+ }
4978
+ }
4979
+ return User;
4980
+ })();
4981
+
4982
+ const user = new User (123 );
4983
+ alert (user .getId ()); // 123
4984
+ user .setId (456 );
4985
+ alert (user .getId ()); // 456
4986
+ ` ` `
4987
+
4988
+ - 这样拿不到弱映射中的健,也就无法取得弱映射中对应的值。
4989
+ - 虽然这防止了前面提到的访问,但整个代码也完全陷入了 ES6 之前的闭包私有变量模式。
4990
+
4991
+ 2. **DOM 节点元数据 **
4992
+
4993
+ - 因为 WeakMap 实例不会妨碍垃圾回收,所以非常适合保存关联元数据。
4994
+
4995
+ - Map 例子:
4996
+
4997
+ ` ` ` javascript
4998
+ const m = new Map ();
4999
+ const loginButton = document .querySelector (' #login' );
5000
+
5001
+ // 给这个节点关联一些元数据
5002
+ m .set (loginButton, {
5003
+ disabled: true
5004
+ });
5005
+ ` ` `
5006
+
5007
+ - 假设在上面的代码执行后,页面被 JavaScript 改变了,原来的登录按钮从 DOM 树中被删掉了。
5008
+ - **但由于映射中还保存着按钮的引用**,所以对应的 DOM 节点仍然会逗留在内存中,除非明确将其从映射中删除或者等到映射本身被销毁。
5009
+
5010
+ - 如果这里使用的是弱映射,如以下代码所示,**那么当节点从 DOM 树中被删除后,垃圾回收程序就可以立即释放其内存**(假设没有其他地方引用这个对象):
5011
+
5012
+ ` ` ` javascript
5013
+ const wm = new WeakMap ();
5014
+ const loginButton = document .querySelector (' #login' );
5015
+
5016
+ // 给这个节点关联一些元数据
5017
+ wm .set (loginButton, {
5018
+ disabled: true
5019
+ });
5020
+ ` ` `
5021
+
5022
+
5023
+
4800
5024
## 6.6 Set
5025
+
5026
+ ECMAScript 6 新增的 Set 是一种新集合类型,为这门语言带来集合数据结构。 Set 在很多方面都像是加强的 Map,这是因为它们的大多数 API 和行为都是共有的。
5027
+
4801
5028
### 6.6.1 基本 API
4802
5029
### 6.6.2 顺序与迭代
4803
5030
### 6.6.3 定义正式集合操作
0 commit comments