Skip to content

Commit 9e97452

Browse files
committed
docs(symbol): edit symbol
1 parent d9b5278 commit 9e97452

File tree

4 files changed

+81
-20
lines changed

4 files changed

+81
-20
lines changed

docs/class.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,9 +740,28 @@ class B extends A {
740740
}
741741
```
742742

743-
上面代码中,子类`B`的构造函数之中的`super()`,代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。`super`虽然代表了父类`A`的构造函数,但是返回的是子类`B`的实例,即`super`内部的`this`指的是`B`,因此`super()`在这里相当于`A.prototype.constructor.call(this)`
743+
上面代码中,子类`B`的构造函数之中的`super()`,代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。
744744

745-
注意,作为函数时,`super()`只能用在子类的构造函数之中,用在其他地方就会报错。
745+
注意,`super`虽然代表了父类`A`的构造函数,但是返回的是子类`B`的实例,即`super`内部的`this`指的是`B`,因此`super()`在这里相当于`A.prototype.constructor.call(this)`
746+
747+
```javascript
748+
class A {
749+
constructor() {
750+
console.log(new.target.name);
751+
}
752+
}
753+
class B extends A {
754+
constructor() {
755+
super();
756+
}
757+
}
758+
new A() // A
759+
new B() // B
760+
```
761+
762+
上面代码中,`new.target`指向当前正在执行的函数名。可以看到,在`super()`执行时,它指向的是子类`B`的构造函数,而不是父类`A`的构造函数。也就是说,`super()`内部的`this`指向的是`B`
763+
764+
作为函数时,`super()`只能用在子类的构造函数之中,用在其他地方就会报错。
746765

747766
```javascript
748767
class A {}

docs/object.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ obj['a' + 'bc'] = 123;
163163

164164
上面代码的方法一是直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在方括号之内。
165165

166-
但是,如果使用字面量方式定义对象(使用大括号),在ES5中只能使用方法一(标识符)定义属性。
166+
但是,如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一(标识符)定义属性。
167167

168168
```javascript
169169
var obj = {
@@ -172,7 +172,7 @@ var obj = {
172172
};
173173
```
174174

175-
ES6允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。
175+
ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。
176176

177177
```javascript
178178
let propKey = 'foo';
@@ -202,7 +202,7 @@ a['last word'] // "world"
202202

203203
```javascript
204204
let obj = {
205-
['h'+'ello']() {
205+
['h' + 'ello']() {
206206
return 'hi';
207207
}
208208
};
@@ -223,7 +223,23 @@ var foo = 'bar';
223223
var baz = { [foo]: 'abc'};
224224
```
225225

226-
## 方法的name属性
226+
注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串`[object Object]`,这一点要特别小心。
227+
228+
```javascript
229+
const keyA = {a: 1};
230+
const keyB = {b: 2};
231+
232+
const myObject = {
233+
[keyA]: 'valueA',
234+
[keyB]: 'valueB'
235+
};
236+
237+
myObject // Object {[object Object]: "valueB"}
238+
```
239+
240+
上面代码中,`[keyA]``[keyB]`得到的都是`[object Object]`,所以`[keyB]`会把`[keyA]`覆盖掉,而`myObject`最后只有一个`[object Object]`属性。
241+
242+
## 方法的 name 属性
227243

228244
函数的`name`属性,返回函数名。对象方法也是函数,因此也有`name`属性。
229245

docs/reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
- Keith Cirkel, [Metaprogramming in ES6: Symbols and why they're awesome](http://blog.keithcirkel.co.uk/metaprogramming-in-es6-symbols/): Symbol的深入介绍
116116
- Axel Rauschmayer, [Customizing ES6 via well-known symbols](http://www.2ality.com/2015/09/well-known-symbols-es6.html)
117117
- Derick Bailey, [Creating A True Singleton In Node.js, With ES6 Symbols](https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/)
118+
- Das Surma, [How to read web specs Part IIa – Or: ECMAScript Symbols](https://dassur.ma/things/reading-specs-2/): 介绍 Symbol 的规格
118119

119120
## Set和Map
120121

docs/symbol.md

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,19 @@ s2.toString() // "Symbol(bar)"
3434

3535
上面代码中,`s1``s2`是两个Symbol值。如果不加参数,它们在控制台的输出都是`Symbol()`,不利于区分。有了参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。
3636

37-
注意,`Symbol`函数的参数只是表示对当前Symbol值的描述,因此相同参数的`Symbol`函数的返回值是不相等的。
37+
如果 Symbol 的参数是一个对象,就会调用该对象的`toString`方法,将其转为字符串,然后才生成一个 Symbol 值。
38+
39+
```javascript
40+
const obj = {
41+
toString() {
42+
return 'abc';
43+
}
44+
};
45+
const sym = Symbol(obj);
46+
sym // Symbol(abc)
47+
```
48+
49+
注意,`Symbol`函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的`Symbol`函数的返回值是不相等的。
3850

3951
```javascript
4052
// 没有参数的情况
@@ -44,8 +56,8 @@ var s2 = Symbol();
4456
s1 === s2 // false
4557

4658
// 有参数的情况
47-
var s1 = Symbol("foo");
48-
var s2 = Symbol("foo");
59+
var s1 = Symbol('foo');
60+
var s2 = Symbol('foo');
4961

5062
s1 === s2 // false
5163
```
@@ -239,9 +251,9 @@ const shapeType = {
239251

240252
## 属性名的遍历
241253

242-
Symbol作为属性名,该属性不会出现在`for...in``for...of`循环中,也不会被`Object.keys()``Object.getOwnPropertyNames()`返回。但是,它也不是私有属性,有一个`Object.getOwnPropertySymbols`方法,可以获取指定对象的所有Symbol属性名
254+
Symbol 作为属性名,该属性不会出现在`for...in``for...of`循环中,也不会被`Object.keys()``Object.getOwnPropertyNames()``JSON.stringify()`返回。但是,它也不是私有属性,有一个`Object.getOwnPropertySymbols`方法,可以获取指定对象的所有 Symbol 属性名
243255

244-
`Object.getOwnPropertySymbols`方法返回一个数组,成员是当前对象的所有用作属性名的Symbol值
256+
`Object.getOwnPropertySymbols`方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值
245257

246258
```javascript
247259
var obj = {};
@@ -281,7 +293,7 @@ Object.getOwnPropertySymbols(obj)
281293

282294
上面代码中,使用`Object.getOwnPropertyNames`方法得不到`Symbol`属性名,需要使用`Object.getOwnPropertySymbols`方法。
283295

284-
另一个新的API,`Reflect.ownKeys`方法可以返回所有类型的键名,包括常规键名和Symbol键名
296+
另一个新的API,`Reflect.ownKeys`方法可以返回所有类型的键名,包括常规键名和 Symbol 键名
285297

286298
```javascript
287299
let obj = {
@@ -294,7 +306,7 @@ Reflect.ownKeys(obj)
294306
// [Symbol(my_key), 'enum', 'nonEnum']
295307
```
296308

297-
由于以Symbol值作为名称的属性,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
309+
由于以 Symbol 值作为名称的属性,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
298310

299311
```javascript
300312
var size = Symbol('size');
@@ -325,7 +337,7 @@ Object.getOwnPropertyNames(x) // ['0']
325337
Object.getOwnPropertySymbols(x) // [Symbol(size)]
326338
```
327339

328-
上面代码中,对象x的size属性是一个Symbol值,所以`Object.keys(x)``Object.getOwnPropertyNames(x)`都无法获取它。这就造成了一种非私有的内部方法的效果。
340+
上面代码中,对象`x``size`属性是一个 Symbol 值,所以`Object.keys(x)``Object.getOwnPropertyNames(x)`都无法获取它。这就造成了一种非私有的内部方法的效果。
329341

330342
## Symbol.for(),Symbol.keyFor()
331343

@@ -338,9 +350,9 @@ var s2 = Symbol.for('foo');
338350
s1 === s2 // true
339351
```
340352

341-
上面代码中,s1和s2都是Symbol值,但是它们都是同样参数的`Symbol.for`方法生成的,所以实际上是同一个值。
353+
上面代码中,`s1``s2`都是 Symbol 值,但是它们都是同样参数的`Symbol.for`方法生成的,所以实际上是同一个值。
342354

343-
`Symbol.for()``Symbol()`这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。`Symbol.for()`不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用`Symbol.for("cat")`30次,每次都会返回同一个Symbol值,但是调用`Symbol("cat")`30次,会返回30个不同的Symbol值。
355+
`Symbol.for()``Symbol()`这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。`Symbol.for()`不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的`key`是否已经存在,如果不存在才会新建一个值。比如,如果你调用`Symbol.for("cat")`30次,每次都会返回同一个 Symbol 值,但是调用`Symbol("cat")`30次,会返回30个不同的Symbol值。
344356

345357
```javascript
346358
Symbol.for("bar") === Symbol.for("bar")
@@ -352,7 +364,7 @@ Symbol("bar") === Symbol("bar")
352364

353365
上面代码中,由于`Symbol()`写法没有登记机制,所以每次调用都会返回一个不同的值。
354366

355-
Symbol.keyFor方法返回一个已登记的Symbol类型值的key
367+
`Symbol.keyFor`方法返回一个已登记的 Symbol 类型值的`key`
356368

357369
```javascript
358370
var s1 = Symbol.for("foo");
@@ -364,7 +376,7 @@ Symbol.keyFor(s2) // undefined
364376

365377
上面代码中,变量`s2`属于未登记的Symbol值,所以返回`undefined`
366378

367-
需要注意的是,`Symbol.for`为Symbol值登记的名字,是全局环境的,可以在不同的iframe或service worker中取到同一个值
379+
需要注意的是,`Symbol.for`为Symbol值登记的名字,是全局环境的,可以在不同的 iframe 或 service worker 中取到同一个值
368380

369381
```javascript
370382
iframe = document.createElement('iframe');
@@ -375,7 +387,7 @@ iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo')
375387
// true
376388
```
377389

378-
上面代码中,iframe窗口生成的Symbol值,可以在主页面得到。
390+
上面代码中,iframe 窗口生成的 Symbol 值,可以在主页面得到。
379391

380392
## 实例:模块的 Singleton 模式
381393

@@ -578,6 +590,17 @@ String.prototype.replace(searchValue, replaceValue)
578590
searchValue[Symbol.replace](this, replaceValue)
579591
```
580592

593+
下面是一个例子。
594+
595+
```javascript
596+
const x = {};
597+
x[Symbol.replace] = (...s) => console.log(s);
598+
599+
'Hello'.replace(x, 'World') // ["Hello", "World"]
600+
```
601+
602+
`Symbol.replace`方法会收到两个参数,第一个参数是`replace`方法正在作用的对象,上面例子是`Hello`,第二个参数是替换后的值,上面例子是`World`
603+
581604
### Symbol.search
582605

583606
对象的`Symbol.search`属性,指向一个方法,当该对象被`String.prototype.search`方法调用时,会返回该方法的返回值。
@@ -681,12 +704,14 @@ String(obj) // 'str'
681704

682705
### Symbol.toStringTag
683706

684-
对象的`Symbol.toStringTag`属性,指向一个方法。在该对象上面调用`Object.prototype.toString`方法时,如果这个属性存在,它的返回值会出现在`toString`方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制`[object Object]``[object Array]`中object后面的那个字符串
707+
对象的`Symbol.toStringTag`属性,指向一个方法。在该对象上面调用`Object.prototype.toString`方法时,如果这个属性存在,它的返回值会出现在`toString`方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制`[object Object]``[object Array]``object`后面的那个字符串
685708

686709
```javascript
710+
// 例一
687711
({[Symbol.toStringTag]: 'Foo'}.toString())
688712
// "[object Foo]"
689713

714+
// 例二
690715
class Collection {
691716
get [Symbol.toStringTag]() {
692717
return 'xxx';

0 commit comments

Comments
 (0)