带你学会ES6中新增的Symbol

169 阅读3分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

前言

Symbol 是ES6 中新增的一个新的原始类型,用来创建必须通过 Symbol才能引用的属性。在学习的过程中对Symbol这块的知识做了一些总结,如果你对JavaScript中这个新的类型还不太熟悉,就来和我一起学习一下吧~~

背景

我们先开看下,为什么会新增这样一个类型,之前的javascript中只有 string, number, boolean, null 和undefined 这五种原始类型,当我们用对象进行属性命名的时候,其key值都是字符串,这样的话就容易造成命名冲突,为了实现私有属性,保证每个属性的名字都不想等,所以新标准中新增了symbol

创建Symbol

Symbol 通过全局的Symbol函数创建。但是Symbol属于原始值,所以,当我们调用 new Symbol()的时候会导致程序抛出错误,也不能给他添加属性

const s = Symbol();
let obj = {};
obj[s] = '私有属性值';
obj // { Symbol(): '私有属性值' }
obj[s] // '私有属性值'
typeof s  // "symbol"

这里我们创建了一个名称为s的symbol,将其作为一个属性给赋值到obj上面,当我们要访问的时候,直接使用最初创建的symbol 来进行访问

当我们创建的时候,还可以给symbol中添加一些描述,用来记录。Symbol的描述被存储在内部的[[ Description]]属性里面,只有当调用他的toString()

方法的时候才可以读取到,在执行console打印的时候,其实是隐式的调用了他的toString方法。当然也可以用实例属性description,来直接返回描述

let s = Symbol('九思')
console.log(s) // Symbol(九思)
s.toString() // Symbol(九思)
s.description // '九思'

如果描述是一个对象的话,则在创建的时候,Symbol 会先调用对象的toString()方法,然后再插入描述

let obj = {age: 18}
obj.toString() // "[object Object]" 
let s = Symbol(obj)
s // Symbol([object Object])

判断Symbol 类型,es6扩展了其对应的typeof 操作符,可以直接判断 typeof Symbol() === "symbol"

由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法,当Symbol 作为属性名的时候,当遍历对象时候,for...in, for...of,Object.keys() 并不会返回Symbol属性名,只能用Object.getOwnPropertySymbols(obj)方法来获取所有的Symbol属性名,该方法返回一个包含所有Symbol自有属性的数组。

Symbol共享

有时候,我们希望在不同的代码中共享同一个Sym bol值,ES6为我们提供了一个随时可以访问的全局Symbol注册表,利用Symbol.for()方法创建。接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值,如果有,就返回这个Symbol值,否则就新建一个将其注册到全局。后续如果传入同样的键调用Symbol.for(),会返回相同的Symbol

let s = Symbol.for('id');
let obj = {
 [s]: '你捉不到的this'
}
s // "Symbol('id')"
let s2 = Symbol.for("id");
s === s2 // true
s2 // "Symbol('id')"

可以使用Symbol.keyFor()方法在Symbol 全局注册表中检索与Symbol 有关的键,如果存在返回ke y,如果不存在返回undefined

let s = Symbol.for('id')
Symbol.keyFor(s) // id
let s = Symbol('id1')
Symbol.keyFor(ss) // undefined