调整字号

ES6 快速上手:Symbol 类型

es6-small

ES5 的时候有六种类型:

  • undefined
  • null
  • Boolean
  • Number
  • String
  • Object

现在,ES6 增加了一种新类型:Symbol。下面是一个创建 symbol 的例子:

var mySymbol = Symbol();
typeof mySymbol; //"symbol"

调用 Symbol 函数就可以创建一个 symbol。因为 symbol 是一个原始类型,并不是对象,所以 new Symbol() 会报错。

symbol 的用处就是作为对象的键。用 symbol 作为对象的键可以避免传统的属性名冲突。比如,用上例的 mySymbol 作为键:

obj[mySymbol] = "ok!"; 

创建 symbol 时,可以传入一个字符串描述:

var sym = Symbol("hi");

即使你每次都传入相同的字符串,返回的 symbol 也互不相等。正因为有这个特性,所以 Symbol 类型可以很好地解决属性名冲突的问题。

什么是冲突呢?当多人合作编码的时候,经常会出现你往对象上加了一个某某属性(比如 $),他人正好也想到了这个名称,当你们同时用了这个名称作为属性,代码之间就会发生冲突,互相覆盖。而用 symbol,即使都用了相同的描述,也不是同一个 symbol。

再列出 Symbol 类型的一些特点:第一,以 symbol 为键的属性,不能用 obj.prop 形式访问,只能用方括号。

第二,for...in 循环、Object.keysObject.getOwnPropertyNames 在遍历一个对象时,都会忽略 symbol 键。

如果你想查看对象上有哪些 symbol 键,可以使用 ES6 的新 API:Object.getOwnPropertySymbols(),返回一个数组,里面都是对象所包含的 symbol。

如果想查看所有属性,用另一个 API:Reflect.ownKeys(obj),会同时返回字符串键和 symbol 键。

第三,in 操作符可以正常工作,比如上例,mySymbol in obj会返回 true。执行 delete obj[mySymbol] 也可以删除这个属性。

第四,symbol 类型不能被自动转换为字符串:

var sym = Symbol("hello");
alert("my symbol is " + sym); // TypeError

可以通过 String(sym) 或调用 sym.toString()

共享 symbol

由于每次调用 Symbol("hello") 返回的 symbol 都是不同的,但有时会有共享同一个 symbol 的需要,所以 ES6 提供了一个全局的 symbol 注册表。

如果你想要共享一个 symbol,用 Symbol.for() 来代替 Symbol()

let sym = Symbol.for("hello");

调用 Symbol.for() 时,如果传入相同的字符串,那么返回的就是同一个 symbol。如果该 symbol 还不存在,则会创建一个 symbol 返回。

Symbol.for() 创建的 symbol 上,还可以调用 Symbol.keyFor() 来查看它的描述。

let sym = Symbol.for("hello");
let sym2 = Symbol.for("hello");
Symbol.keyFor(sym); //"hello"
Symbol.keyFor(sym2); //"hello"

let sym3 = Symbol("hello");
Symbol.keyFor(sym3); // undefined

你可以看到在一个普通 Symbol() 创建的 symbol 上调用 Symbol.keyFor() 会发生什么。

内置 symbol

ES6 内置了一些 symbol,它们都作为 Symbol 函数的属性存在,比如后面关于迭代器文章里要提到的 Symbol.iterator。但是,调用 Object.getOwnPropertySymbols() 时,这些内置 symbol 不被计算在内。

还没有评论,沙发空缺中……
flight