防止属性名的冲突。这就是 ES6 引入Symbol
的原因。
它是 JavaScript 语言的第七种数据类型,前六种是:undefined
、null
、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
var s1 = Symbol('foo'); var s2 = Symbol('bar'); s1 // Symbol(foo) s2 // Symbol(bar) s1.toString() // "Symbol(foo)" s2.toString() // "Symbol(bar)"
注意,Symbol
函数前不能使用new
命令,否则会报错。
Symbol 值不能与其他类型的值进行运算,会报错。
Symbol 值可以显式转为字符串。
var sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)'
1.作为属性名的 Symbol
Symbol 值作为对象属性名时,不能用点运算符
var mySymbol = Symbol(); var a = {}; a.mySymbol = 'Hello!'; a[mySymbol] // undefined a['mySymbol'] // "Hello!"
在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
let s = Symbol(); let obj = { [s]: function (arg) { ... } }; obj[s](123);
上面代码中,如果s
不放在方括号中,该属性的键名就是字符串s
,而不是s
所代表的那个 Symbol 值。
2.实例:消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。
风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
function getArea(shape, options) { var area = 0; switch (shape) { case 'Triangle': // 魔术字符串 area = .5 * options.width * options.height; break; /* ... more code ... */ } return area; } getArea('Triangle', { 100, height: 100 }); // 魔术字符串
常用的消除魔术字符串的方法,就是把它写成一个变量。
const shapeType = { triangle: Symbol() }; function getArea(shape, options) { var area = 0; switch (shape) { case shapeType.triangle: area = .5 * options.width * options.height; break; } return area; } getArea(shapeType.triangle, { 100, height: 100 });
3.属性名的遍历
Object.getOwnPropertySymbols
方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
var obj = {}; var foo = Symbol("foo"); Object.defineProperty(obj, foo, { value: "foobar", }); for (var i in obj) { console.log(i); // 无输出 } Object.getOwnPropertyNames(obj) // [] Object.getOwnPropertySymbols(obj) // [Symbol(foo)]
另一个新的API,Reflect.ownKeys
方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
4.Symbol.for(),Symbol.keyFor()
我们希望重新使用同一个Symbol值,Symbol.for
方法可以做到这一点
var s1 = Symbol.for('foo'); var s2 = Symbol.for('foo'); s1 === s2 // true
Symbol.for()
与Symbol()
这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。
Symbol.keyFor
方法返回一个已登记的 Symbol 类型值的key
。
var s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" var s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined
需要注意的是,Symbol.for
为Symbol值登记的名字,是全局环境的,可以在不同的 iframe 或 service worker 中取到同一个值。