第十章 Symbol
参考资料:《ES6标准入门第3版》
10.1 概述
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined
、null
、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
1. Symbol 值通过 Symbol 函数生成,数据类型是 Symbol。
let s = Symbol();
console.log(typeof s) // "symbol"
2. Symbol 函数不能使用 new 命令,否则会报错。
let s = new Symbol();
// TypeError: Symbol is not a constructor
3. Symbol 函数可以接受一个字符串参数,表示对变量的描述,输出的时候可以区分是哪一个变量。
let s = Symbol('s');
let q = Symbol('q');
console.log(s,q)
// Symbol(s) Symbol(q)
4. 每一个通过Symbol函数生成的值都是唯一的,无论参数是否相同,它们都不相等。
通过Symbol方法生成的值,无论生成多少次,无论参数是否相同,它们都不相等
let s = Symbol();
let q = Symbol();
console.log(s === q) // false
let s = Symbol('q');
let q = Symbol('q');
console.log(s === q) // false
但是通过Symbol.for() 方法可以生成同一个Symbol值。有时,我们希望重新使用同一个 Symbol 值,Symbol.for() 方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
console.log(s1 === s2); // true
上面代码中,s1
和s2
都是 Symbol 值,但是它们都是同样参数的Symbol.for
方法生成的,所以实际上是同一个值。
5.Symbol值不参与其他类型值的运算,否则会报错,但是可以显式地转为字符串
let sym = Symbol('My symbol');
"your symbol is " + sym
// TypeError: can't convert symbol to string
String(sym) // 'Symbol(My symbol)'
10.2 Symbol的使用-作为对象的属性名
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
Symbol作为对象属性名的时候不能通过点运算符来访问。
let mySymbol = Symbol();
let a = {};
a[mySymbol] = 'Hello!';
console.log(a[mySymbol]) // Hello!
console.log(a.mySymbol) // undefined
在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
let s = Symbol();
let obj = {
[s]: function (a) { console.log(a+2) }
};
obj[s](3); // 5
因为对象点运算符后面总是字符串,而不会读取Symbol边量作为标识名所指代的值。在对象内部把Symbol值放在方括号中也是为了避免被认为是字符串类型的方法名。
10.3 Symbol的使用-消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
function getType(type){
switch(type){
case "square":console.log("正方形");break;
case "triangle":console.log("三角形");break;
}
}
getType("square") // 正方形
上面代码中,字符串square
就是一个魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。
const shapeType = {
square: 'square',
triangle:'triangle'
};
function getType(type){
switch(type){
case shapeType.square:console.log("正方形");break;
case shapeType.triangle:console.log("三角形");break;
}
}
getType(shapeType.triangle) // 三角形
如果仔细分析,可以发现shapeType.triangle
等于哪个值并不重要,只要确保不会跟其他shapeType
属性的值冲突即可。因此,这里就很适合改用 Symbol 值。
const shapeType = {
square: Symbol(),
triangle:Symbol()
};
function getType(type){
switch(type){
case shapeType.square:console.log("正方形");break;
case shapeType.triangle:console.log("三角形");break;
}
}
getType(shapeType.triangle) // 三角形
10.4 属性名的遍历
Symbol 作为属性名,该属性不会出现在for...in
、for...of
循环中,也不会被Object.keys()、
Object.getownPropertyNames()
、JSON.stringify()
返回。但是,它也不是私有属性,有一个Object.getownPropertySymbols
方法,可以获取指定对象的所有 Symbol 属性名。
const obj = {};
let foo = Symbol("foo");
obj[foo] = "foo"
for (let i in obj) {
console.log(i); // 无输出
}
console.log(JSON.stringify(obj));
// {}
console.log(Object.keys(obj));
// []
console.log(Object.getownPropertyNames(obj));
// []
console.log(Object.getownPropertySymbols(obj));
// [Symbol(foo)]
从上面的例子可以得知,使用常规的遍历方法无法得到Symbol属性名,只有使用一些特定的遍历方法才能得到 Symbol 定义的属性名。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。