你不知道的 Symbol 类型

253 阅读2分钟

最近重温ES6,发现对Symbol一知半解,写篇文章加深下印象。

Symbol 概述

Symbol是 ES6 新增原始数据类型,表示独一无二的值。为什么要引进Symbol呢?
原因就是ES5中对象的属性都是字符串,容易造成属性冲突。为了保证属性名的独一无二,防止属性名冲突,由此Symbol被引入。

基本使用

Symbol 值通过Symbol函数生成,凡是属性名属于 Symbol 类型,就都是独一无二的。Symbol类型唯一合理的用法是用变量存储symbol的值,然后使用存储的值创建对象属性。注意,因为Symbol是原始数据类型,Symbol函数前不能使用new命令,否则会报错。

let s = Symbol();
let s1 = Symbol("s");
let s2 = Symbol("s");
let s3 = new Symbol("s") // Symbol is not a constructor
console.log(s === s1); //false
console.log(s1 === s2); //false

let obj = {};
let prop = Symbol();
obj[prop] = 1;
console.log(obj[prop]); // 1
console.log(Object.keys(obj)); // []

属性

ES6 还提供了一些内置的 Symbol 值,指向语言内部使用的方法。这里介绍几个,具体的可以去MDN上再查看。

  • Symbol.iterator:属性本身是一个函数,当前数据结构默认的比遍历器生成函数。执行这个函数就会返回一个遍历器,被for...of使用

  • Symbol.hasInstance: 当其他对象使用instanceof运算符,判断是否为该对象实例时,会调用此方法。例:foo instanceof Foo 在语言内部,调用的就是属性内部的Symbol.hasInstance方法。

  • Symbol.toPrimitive:作为对象的函数值属性存在的,当一个对象转换为对应原始值时,会调用此函数。ES6之后提供,优先级最高。这里就涉及到隐式转换的概念,大家有兴趣可以更深入的了解。

这里就有道经典的题目出现了, 例:a == 1&&a==2&&a==3(重写valueOf/Symbol.toPrimitive)问题。

const a = { value:0 }
a[Symbol.toPrimitive] = function(){
    return this.value += 1
}
console.log(a==1&&a==2&&a==3) // true

方法

  • Symbol.for(): 某些时候,我们希望重新使用同一个 Symbol 值,Symbol.for()可以做到。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 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.kyeFor(): 返回一个已登记的 Symbol 类型值的key。注意:如果查询的没有注册全局,则会返回 undefied。
let s = Symbol('foo')
console.log(Symbol.keyFor(s)) // undefined

以上就是我对Symbol的一些整理,希望对大家有些许帮助。