mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 18:32:22 +00:00
docs(symbol): edit symbol
This commit is contained in:
parent
15b962627e
commit
b2182920bb
@ -723,7 +723,7 @@ let arr = [...obj]; // TypeError: Cannot spread non-iterable object
|
|||||||
|
|
||||||
## 严格模式
|
## 严格模式
|
||||||
|
|
||||||
从ES5开始,函数内部可以设定为严格模式。
|
从 ES5 开始,函数内部可以设定为严格模式。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function doSomething(a, b) {
|
function doSomething(a, b) {
|
||||||
@ -732,7 +732,7 @@ function doSomething(a, b) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
《ECMAScript 2016标准》做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
|
ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 报错
|
// 报错
|
||||||
@ -762,7 +762,7 @@ const obj = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
这样规定的原因是,函数内部的严格模式,同时适用于函数体代码和函数参数代码。但是,函数执行的时候,先执行函数参数代码,然后再执行函数体代码。这样就有一个不合理的地方,只有从函数体代码之中,才能知道参数代码是否应该以严格模式执行,但是参数代码却应该先于函数体代码执行。
|
这样规定的原因是,函数内部的严格模式,同时适用于函数体和函数参数。但是,函数执行的时候,先执行函数参数,然后再执行函数体。这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 报错
|
// 报错
|
||||||
@ -772,7 +772,7 @@ function doSomething(value = 070) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,参数`value`的默认值是八进制数`070`,但是严格模式下不能用前缀`0`表示八进制,所以应该报错。但是实际上,JavaScript引擎会先成功执行`value = 070`,然后进入函数体内部,发现需要用严格模式执行,这时才会报错。
|
上面代码中,参数`value`的默认值是八进制数`070`,但是严格模式下不能用前缀`0`表示八进制,所以应该报错。但是实际上,JavaScript 引擎会先成功执行`value = 070`,然后进入函数体内部,发现需要用严格模式执行,这时才会报错。
|
||||||
|
|
||||||
虽然可以先解析函数体代码,再执行参数代码,但是这样无疑就增加了复杂性。因此,标准索性禁止了这种用法,只要参数使用了默认值、解构赋值、或者扩展运算符,就不能显式指定严格模式。
|
虽然可以先解析函数体代码,再执行参数代码,但是这样无疑就增加了复杂性。因此,标准索性禁止了这种用法,只要参数使用了默认值、解构赋值、或者扩展运算符,就不能显式指定严格模式。
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 属性的简洁表示法
|
## 属性的简洁表示法
|
||||||
|
|
||||||
ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
|
ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var foo = 'bar';
|
var foo = 'bar';
|
||||||
@ -1066,7 +1066,7 @@ y // undefined
|
|||||||
z // 3
|
z // 3
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,变量`x`是单纯的解构赋值,所以可以读取继承的属性;解构赋值产生的变量`y`和`z`,只能读取对象自身的属性,所以只有变量`z`可以赋值成功。
|
上面代码中,变量`x`是单纯的解构赋值,所以可以读取对象`o`继承的属性;变量`y`和`z`是双重解构赋值,只能读取对象`o`自身的属性,所以只有变量`z`可以赋值成功。
|
||||||
|
|
||||||
解构赋值的一个用处,是扩展某个函数的参数,引入其他操作。
|
解构赋值的一个用处,是扩展某个函数的参数,引入其他操作。
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
## 概述
|
## 概述
|
||||||
|
|
||||||
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
|
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入`Symbol`的原因。
|
||||||
|
|
||||||
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
|
ES6 引入了一种新的原始数据类型`Symbol`,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:`undefined`、`null`、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
|
||||||
|
|
||||||
Symbol值通过`Symbol`函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
|
Symbol 值通过`Symbol`函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let s = Symbol();
|
let s = Symbol();
|
||||||
@ -15,11 +15,11 @@ typeof s
|
|||||||
// "symbol"
|
// "symbol"
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,变量`s`就是一个独一无二的值。`typeof`运算符的结果,表明变量`s`是Symbol数据类型,而不是字符串之类的其他类型。
|
上面代码中,变量`s`就是一个独一无二的值。`typeof`运算符的结果,表明变量`s`是 Symbol 数据类型,而不是字符串之类的其他类型。
|
||||||
|
|
||||||
注意,`Symbol`函数前不能使用`new`命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。也就是说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
|
注意,`Symbol`函数前不能使用`new`命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
|
||||||
|
|
||||||
`Symbol`函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
|
`Symbol`函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var s1 = Symbol('foo');
|
var s1 = Symbol('foo');
|
||||||
@ -32,7 +32,7 @@ s1.toString() // "Symbol(foo)"
|
|||||||
s2.toString() // "Symbol(bar)"
|
s2.toString() // "Symbol(bar)"
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,`s1`和`s2`是两个Symbol值。如果不加参数,它们在控制台的输出都是`Symbol()`,不利于区分。有了参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。
|
上面代码中,`s1`和`s2`是两个 Symbol 值。如果不加参数,它们在控制台的输出都是`Symbol()`,不利于区分。有了参数以后,就等于为它们加上了描述,输出的时候就能够分清,到底是哪一个值。
|
||||||
|
|
||||||
如果 Symbol 的参数是一个对象,就会调用该对象的`toString`方法,将其转为字符串,然后才生成一个 Symbol 值。
|
如果 Symbol 的参数是一个对象,就会调用该对象的`toString`方法,将其转为字符串,然后才生成一个 Symbol 值。
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ s1 === s2 // false
|
|||||||
|
|
||||||
上面代码中,`s1`和`s2`都是`Symbol`函数的返回值,而且参数相同,但是它们是不相等的。
|
上面代码中,`s1`和`s2`都是`Symbol`函数的返回值,而且参数相同,但是它们是不相等的。
|
||||||
|
|
||||||
Symbol值不能与其他类型的值进行运算,会报错。
|
Symbol 值不能与其他类型的值进行运算,会报错。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var sym = Symbol('My symbol');
|
var sym = Symbol('My symbol');
|
||||||
@ -75,7 +75,7 @@ var sym = Symbol('My symbol');
|
|||||||
// TypeError: can't convert symbol to string
|
// TypeError: can't convert symbol to string
|
||||||
```
|
```
|
||||||
|
|
||||||
但是,Symbol值可以显式转为字符串。
|
但是,Symbol 值可以显式转为字符串。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var sym = Symbol('My symbol');
|
var sym = Symbol('My symbol');
|
||||||
@ -84,7 +84,7 @@ String(sym) // 'Symbol(My symbol)'
|
|||||||
sym.toString() // 'Symbol(My symbol)'
|
sym.toString() // 'Symbol(My symbol)'
|
||||||
```
|
```
|
||||||
|
|
||||||
另外,Symbol值也可以转为布尔值,但是不能转为数值。
|
另外,Symbol 值也可以转为布尔值,但是不能转为数值。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var sym = Symbol();
|
var sym = Symbol();
|
||||||
@ -99,9 +99,9 @@ Number(sym) // TypeError
|
|||||||
sym + 2 // TypeError
|
sym + 2 // TypeError
|
||||||
```
|
```
|
||||||
|
|
||||||
## 作为属性名的Symbol
|
## 作为属性名的 Symbol
|
||||||
|
|
||||||
由于每一个Symbol值都是不相等的,这意味着Symbol值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
|
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var mySymbol = Symbol();
|
var mySymbol = Symbol();
|
||||||
@ -123,9 +123,9 @@ Object.defineProperty(a, mySymbol, { value: 'Hello!' });
|
|||||||
a[mySymbol] // "Hello!"
|
a[mySymbol] // "Hello!"
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码通过方括号结构和`Object.defineProperty`,将对象的属性名指定为一个Symbol值。
|
上面代码通过方括号结构和`Object.defineProperty`,将对象的属性名指定为一个 Symbol 值。
|
||||||
|
|
||||||
注意,Symbol值作为对象属性名时,不能用点运算符。
|
注意,Symbol 值作为对象属性名时,不能用点运算符。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var mySymbol = Symbol();
|
var mySymbol = Symbol();
|
||||||
@ -136,9 +136,9 @@ a[mySymbol] // undefined
|
|||||||
a['mySymbol'] // "Hello!"
|
a['mySymbol'] // "Hello!"
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,因为点运算符后面总是字符串,所以不会读取`mySymbol`作为标识名所指代的那个值,导致`a`的属性名实际上是一个字符串,而不是一个Symbol值。
|
上面代码中,因为点运算符后面总是字符串,所以不会读取`mySymbol`作为标识名所指代的那个值,导致`a`的属性名实际上是一个字符串,而不是一个 Symbol 值。
|
||||||
|
|
||||||
同理,在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中。
|
同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let s = Symbol();
|
let s = Symbol();
|
||||||
@ -150,7 +150,7 @@ let obj = {
|
|||||||
obj[s](123);
|
obj[s](123);
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,如果`s`不放在方括号中,该属性的键名就是字符串`s`,而不是`s`所代表的那个Symbol值。
|
上面代码中,如果`s`不放在方括号中,该属性的键名就是字符串`s`,而不是`s`所代表的那个 Symbol 值。
|
||||||
|
|
||||||
采用增强的对象写法,上面代码的`obj`对象可以写得更简洁一些。
|
采用增强的对象写法,上面代码的`obj`对象可以写得更简洁一些。
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ let obj = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Symbol类型还可以用于定义一组常量,保证这组常量的值都是不相等的。
|
Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
log.levels = {
|
log.levels = {
|
||||||
@ -190,9 +190,9 @@ function getComplement(color) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
常量使用Symbol值最大的好处,就是其他任何值都不可能有相同的值了,因此可以保证上面的`switch`语句会按设计的方式工作。
|
常量使用 Symbol 值最大的好处,就是其他任何值都不可能有相同的值了,因此可以保证上面的`switch`语句会按设计的方式工作。
|
||||||
|
|
||||||
还有一点需要注意,Symbol值作为属性名时,该属性还是公开属性,不是私有属性。
|
还有一点需要注意,Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。
|
||||||
|
|
||||||
## 实例:消除魔术字符串
|
## 实例:消除魔术字符串
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ function getArea(shape, options) {
|
|||||||
getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
|
getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,字符串“Triangle”就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。
|
上面代码中,字符串`Triangle`就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。
|
||||||
|
|
||||||
常用的消除魔术字符串的方法,就是把它写成一个变量。
|
常用的消除魔术字符串的方法,就是把它写成一个变量。
|
||||||
|
|
||||||
@ -237,9 +237,9 @@ function getArea(shape, options) {
|
|||||||
getArea(shapeType.triangle, { width: 100, height: 100 });
|
getArea(shapeType.triangle, { width: 100, height: 100 });
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,我们把“Triangle”写成`shapeType`对象的`triangle`属性,这样就消除了强耦合。
|
上面代码中,我们把`Triangle`写成`shapeType`对象的`triangle`属性,这样就消除了强耦合。
|
||||||
|
|
||||||
如果仔细分析,可以发现`shapeType.triangle`等于哪个值并不重要,只要确保不会跟其他`shapeType`属性的值冲突即可。因此,这里就很适合改用Symbol值。
|
如果仔细分析,可以发现`shapeType.triangle`等于哪个值并不重要,只要确保不会跟其他`shapeType`属性的值冲突即可。因此,这里就很适合改用 Symbol 值。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const shapeType = {
|
const shapeType = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user