《现代 JavaScript 教程 》Symbol
Symbol
类型作为ES5新增的一种基本数据类型。每个从 Symbol()
返回的symbol值都是唯一的。Symbol不支持语法 "new Symbol()"
const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');
console.log(typeof symbol1);
// expected output: "symbol"
console.log(symbol2 === 42);
// expected output: false
console.log(symbol3.toString());
// expected output: "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo'));
JavaScript中大多数数值类型支持字符串的隐式转换,但 Symbol
比较特殊,不会被自动转换为字符串。
如果想返回当前 symbol
对象的字符串表示,请使用 Symbol.prototype.toString()
Symbol("desc").toString(); // "Symbol(desc)"
// well-known symbols
Symbol.iterator.toString(); // "Symbol(Symbol.iterator)
// global symbols
Symbol.
description
是一个只读属性,它会返回 Symbol
对象的可选描述的字符串。
console.log(Symbol('desc').description);
// expected output: "desc"
console.log(Symbol.iterator.description);
// expected output: "Symbol.iterator"
console.log(Symbol.for('foo').description);
// expected output: "foo"
console.log(`${Symbol('foo').description}bar`);
"隐藏"属性
Symbol
允许我们创建对象的"隐藏"属性,代码的任何其他部分都不能意外访问或重写这些属性。
使用 Symbol("id") 作为键,比起用字符串 "id" 来有什么好处呢? 因为 user 对象属于其他的代码,那些代码也会使用这个对象,所以我们不应该在它上面直接添加任何字段,这样很不安全。但是你添加的 Symbol 属性不会被意外访问到,第三方代码根本不会看到它,所以使用 Symbol 基本上不会有问题。
如果我们要在对象字面量 {...}
中使用 Symbol,则需要使用方括号把它括起来。
let id = Symbol("id");
let user = {
name: "John",
[id]: 123 // 而不是 "id":123
};
Symbol 属性不参与 for..in
循环, Object.keys(user)
也会忽略它们
全局Symbol
`
Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol
var sym = Symbol.for("mario");
sym.toString();
类似的,对于全局Symbol,不仅有 Symbol.for(key)
按名字返回一个 Symbol,还有一个反向调用: Symbol.keyFor(sym)
方法用来获取全局symbol 注册表中与某个 symbol 关联的键。
// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
var localSym = Symbol();
Symbol.keyFor(localSym); // undefined,
// 以下Symbol不是保存在全局Symbol注册表中
Symbol.keyFor(Symbol.iterator)
系统Symbol
JavaScript 内部有很多"系统" Symbol