Symbol
Symbol相关特点
- Symbol 是 ES6 新增了第 7 种原始数据类型 Symbol,。语义为:
独一无二的值
。 - Symbol() 函数会返回 symbol 类型的值,该类型具有静态属性和静态方法。
- 每个从 Symbol() 返回的 symbol 值都是唯一的。
- 它的静态属性会暴露几个内建的成员对象。
- 它的静态方法会暴露全局的 symbol 注册。
构造函数
- Symbol() 构造函数返回一个 symbol 类型的值,但是它并不完全支持构造函数的语法
new Symbol()
。 - 无法被子类化,它可以作为 class 定义中 extends 子句的值使用,但对它进行 super 调用将会导致异常。
javascript
const sym1 = Symbol();
const sym2 = Symbol("foo");
const sym3 = Symbol("foo");
const sym1 = Symbol();
const sym2 = Symbol("foo");
const sym3 = Symbol("foo");
注意:Symbol("foo") 不会将字符串 "foo" 强制转换成 symbol,而是每次总是创建一个新的 symbol;
静态方法
Symbol.for()
- 描述:Symbol.for(key) 方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol。如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
javascript
Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
Symbol.for("foo") = Symbol.for("foo") // true
Symbol("bar") === Symbol("bar"); // false Symbol() 函数每次都会返回新的一个 symbol
Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
Symbol.for("foo") = Symbol.for("foo") // true
Symbol("bar") === Symbol("bar"); // false Symbol() 函数每次都会返回新的一个 symbol
和 Symbol() 不同的是,用 Symbol.for() 方法创建的 symbol 会被放入一个全局 symbol 注册表中。
全局 symbol 注册表中的记录结构:
字段名 | 字段值 |
---|---|
[key] | 一个字符串,用来标识每个 symbol |
[symbol] | 存储的 symbol 值 |
Symbol.keyFor(sym)
- 描述:Symbol.keyFor(sym) 方法用来获取全局 symbol 注册表中与某个 symbol 关联的键。
- 参数:必选参数,需要查找键值的某个 Symbol。
- 返回:如果全局注册表中查找到该 symbol,则返回该 symbol 的 key 值,返回值为字符串类型。否则返回 undefined
js
// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
Symbol的应用
场景一:作为对象属性名(key)
- Symbol 作为属性名,该属性无法被 for...in、for...of 、Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 这些方法获取。只有Object.getOwnPropertySymbols()方法可以获取指定对象的所有 Symbol 属性名。
javascript
//symbol作为对象属性
let obj_name = Symbol("name");
let obj = {
[obj_name]: "Bob",
name: "bob",
age: 18,
sex: "man",
};
//symbol作为对象属性
let obj_name = Symbol("name");
let obj = {
[obj_name]: "Bob",
name: "bob",
age: 18,
sex: "man",
};
场景二:消除魔法字符
javascript
// 代替常量,消除魔法字符。
const TYPE_AUDIO = "AUDIO";
const TYPE_VIDEO = "VIDEO";
const TYPE_IMAGE = "IMAGE";
// Symbol消除与业务代码无关的魔法字符。
const TYPE_AUDIO = Symbol();
const TYPE_VIDEO = Symbol();
const TYPE_IMAGE = Symbol();
// 代替常量,消除魔法字符。
const TYPE_AUDIO = "AUDIO";
const TYPE_VIDEO = "VIDEO";
const TYPE_IMAGE = "IMAGE";
// Symbol消除与业务代码无关的魔法字符。
const TYPE_AUDIO = Symbol();
const TYPE_VIDEO = Symbol();
const TYPE_IMAGE = Symbol();
场景三:定义类的私有属性/方法
javascript
class MyClass {
// 定义私有属性和方法的 Symbol
#privateProperty = Symbol('privateProperty');
#privateMethod = Symbol('privateMethod');
constructor(value) {
// 使用 Symbol 定义私有属性
this[this.#privateProperty] = value;
}
// 使用 Symbol 定义私有方法
[this.#privateMethod]() {
console.log('This is a private method');
}
// 公共方法访问私有属性和方法
publicMethod() {
console.log('Private Property:', this[this.#privateProperty]);
this[this.#privateMethod]();
}
}
const instance = new MyClass('secret');
instance.publicMethod();
// 输出: Private Property: secret
// 输出: This is a private method
// 无法直接访问私有属性和方法
console.log(instance.privateProperty); // undefined
console.log(instance.privateMethod); // undefined
class MyClass {
// 定义私有属性和方法的 Symbol
#privateProperty = Symbol('privateProperty');
#privateMethod = Symbol('privateMethod');
constructor(value) {
// 使用 Symbol 定义私有属性
this[this.#privateProperty] = value;
}
// 使用 Symbol 定义私有方法
[this.#privateMethod]() {
console.log('This is a private method');
}
// 公共方法访问私有属性和方法
publicMethod() {
console.log('Private Property:', this[this.#privateProperty]);
this[this.#privateMethod]();
}
}
const instance = new MyClass('secret');
instance.publicMethod();
// 输出: Private Property: secret
// 输出: This is a private method
// 无法直接访问私有属性和方法
console.log(instance.privateProperty); // undefined
console.log(instance.privateMethod); // undefined