Symbol.for()
是 Symbol
的静态方法,该方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
Symbol.for(key);
和 Symbol()
不同的是,用 Symbol.for()
方法创建的 symbol 会被放入一个全局 symbol 注册表中。Symbol.for()
并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
因此 Symbol()
即使是传入相同的 key ,每次返回的都是新的 symbol 类型的值。而 Symbol.for()
传入相同的 key,返回的是同一个 symbol 类型的值:
使用 Symbol.for()
创建 symbol 类型的值时,为了防止命名冲突,比如与其他代码库的命名冲突,建议给传入 Symbol.for
方法的 key 加上前缀:
// packages/runtime-core/src/vnode.ts
export const Text: unique symbol = Symbol.for('v-txt')
export const Comment: unique symbol = Symbol.for('v-cmt')
export const Static: unique symbol = Symbol.for('v-stc')
上述代码摘自 Vue.js 3.5.5 版本
Symbol.for()
有个与之对应的兄弟方法 Symbol.keyFor()
。
Symbol.keyFor()
方法用来获取全局 symbol 注册表中与某个 symbol 关联的 key 。因此可用该方法判断相关 symbol 值是否为用 Symbol.for()
创建的:
let a = Symbol("a")
let b = Symbol.for("a")
Symbol.keyFor(a) // undefined ,说明该 symbol 值不是用 Symbol.for 创建的
Symbol.keyFor(b) // 'a'
使用 Symbol.for()
方法创建的 symbol 类型的值会存储到全局的 symbol 注册表中,因此无法被垃圾回收,同时 Symbol.for()
方法创建的 symbol 类型的值不能作为 WeakMap
、WeakSet
、WeakRef
和 FinalizationRegistry
的 key 。
WeakMap
的示例:
WeakSet
的示例:
WeakRef
的示例:
FinalizationRegistry
的示例:
可以看到,使用 Symbol.for()
方法创建的 symbol 类型的值作为 WeakMap
、WeakSet
、WeakRef
和 FinalizationRegistry
的 key 时,都会报错。
但是 Symbol()
函数创建的 symbol 类型的值,可以作为 WeakMap
、WeakSet
、WeakRef
和 FinalizationRegistry
的 key ,因为使用 Symbol()
函数创建的 symbol 类型的值可以被垃圾回收。
WeakMap
的示例:
WeakSet
的示例:
WeakRef
的示例:
FinalizationRegistry
的示例:
总结
Symbol()
与 Symbol.for()
的区别在于:
-
Symbol()
即使重复定义,也不会产生重复的 symbol 类型的值 -
Symbol.for()
在创建 symbol 类型的值之前会先使用 key 在全局 symbol 注册表中查找是否存在 symbol 值,如果存在,则返回在全局 symbol 注册表中的 symbol 值。即Symbol.for()
不会重复定义 symbol 值,如果重复定义,则返回之前定义过的 symbol 值。