重学JS-4-Symbol

99 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

前端开发的第三年,突然发现,对于JS,我还有很多不懂的地方,趁着最近需求少,不如静下心来,从头把JS再学一遍,查漏补缺。

本系列以廖雪峰的《JavaScript教程》和《现代 JavaScript 教程》两个电子书作为线索,对其中需要进一步了解的知识,会阅读更多的文章,并作为扩展知识记录下来。

新手建议先阅读上面两个电子书,本系列更适合用来复习旧知识查漏补缺

思维导图

通过下面的思维导图,我们先对JavaScript的Symbol有一些基本的了解。

《重学JavaScript》思维导图.png

Symbol是什么?

stringnumber一样,Symbol也是一种基本数据类型。

Symbol的作用是作为一个唯一的标识符

Symbol的特点

Symbol没有字面量,只能用Symbol()函数创建

创建时,我们可以选择给Symbol一个描述,但这个描述只是用于调试,没有实质的作用。

// id 是 symbol 的一个实例化对象
let id = Symbol();
// id 是描述为 "id" 的 Symbol
let id = Symbol("id");

怎么获取这个描述呢,下面有两种方式。

let id = Symbol("id");
alert(id.toString()); // Symbol(id),现在它有效了
alert(id.description); // id

Symbol是唯一的

即使描述一样,两个Symbol也是不相等的。

let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false

Symbol创建的属性,会被for-in跳过

同理,Object.keys也会跳过Symbol。

但是Object.assign拷贝时,Symbol还是会被复制。

let id = Symbol("id");
let user = {
  name: "John",
  age: 30,
  [id]: 123
};

for (let key in user) alert(key); // name, age (no symbols)

Symbol.for(key)创建全局Symbol

全局Symbol,key相同的时候,值也是相同的。

Symbol.for,如果同名Symbol已存在,就返回,如果不存在,就创建一个。

// 从全局注册表中读取
let id = Symbol.for("id"); // 如果该 Symbol 不存在,则创建它

// 再次读取(可能是在代码中的另一个位置)
let idAgain = Symbol.for("id");

// 相同的 Symbol
alert( id === idAgain ); // true

Symbol.keyFor(sym)获取Symbol的key

如果Symbol是全局的,返回key,否则返回undefined

let globalSymbol = Symbol.for("name");
let localSymbol = Symbol("name");

alert( Symbol.keyFor(globalSymbol) ); // name,全局 Symbol
alert( Symbol.keyFor(localSymbol) ); // undefined,非全局

alert( localSymbol.description ); // name

Symbol的适用场景

Symbol做唯一值

Symbol做唯一值,可以替换字符串和整型(魔法数)。

log.levels = {
    DEBUG: Symbol('debug'),
    INFO: Symbol('info'),
    WARN: Symbol('warn'),
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');

Symbol用于创建对象的“隐藏属性“

对象的属性的key,可以是字符串Symbol,Symbol属性在很多情况下,是不可见的。

let user = { // 属于另一个代码
  name: "John"
};

let id = Symbol("id");

user[id] = 1;

alert( user[id] ); // 我们可以使用 Symbol 作为键来访问数据

注意,在对象字面量中使用Symbol,需要把它用方括号括起来。

let id = Symbol("id");

let user = {
  name: "John",
  [id]: 123 // 而不是 "id":123
};

用系统Symbol来微调对象。

JavaScript内置了一些内部的系统Symbol,通过这些Symbol,我们可以修改对象的一些行为。

比如下面这个例子,我们用Symbol.ierator 重写 of 运算符。

class Collection {
  *[Symbol.iterator]() {
    var i = 0;
    while(this[i] !== undefined) {
      yield this[i];
      ++i;
    }
  }

}
var myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;
for(var value of myCollection) {
    console.log(value); // 1, then 2
}