ES6 - symbol类型

avatar
前端工程师 @豌豆公主

Symbol

在聊symbol类型的时候,顺便一起回忆一下js中的数据类型

  • 原始值类型 「值类型/基本数据类型」

    • number
    • string
    • boolean
    • null
    • undefined
    • symbol
    • bigint
  • 对象类型 「引用数据类型」

    • 普通标准对象 object
    • 标准特殊对象 Array, RegExp, Date, Math, Error...
    • 非标准特殊对象Number, String, Boolean...
    • 可调用/执行对象「函数」 function 在ES6,以及之后,原始数据类型引入了symbol,bigint。

引入symbol:symbol的主要特性是唯一性,可以避免属性名之间的冲突

bigint:bigint的主要应用是解决当前最大数的限制,可以处理更大数据

今天就着重给大家聊一个Symbol

Symbol基础知识

Symbol(符号).符号可以像字符串那样作为对象的属性名,只是他有唯一性,可以避免属性名之间的冲突

  1. 语法

Symbol( [description] )
  • 每个从 Symbol() 返回的 symbol 值都是唯一的

image.png

  • 我们可以写无数个 Symbol()他们都是唯一的,但是怎么去区分呢🤔,可以添加一个description。这仅仅是描述,并不能以此来访问 symbol 本身

image.png 2. Symbo()不能 被 new

image.png

  • 原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持。 然而,现有的原始包装器对象,如 new Booleannew String以及new Number,因为遗留原因仍可被创建。 对于ES6中新增的另一种数据类型bigint呢? 也是一样滴 😄

image.png

如果真的想创建一个 Symbol 包装器对象,可以使用 Object() 函数

image.png

image.png

  1. 全局共享的 Symbol

每个从 Symbol() 返回的 symbol 值都是唯一的。但是如果想共享值呢?🤔 要共享的值要用Symbol.for()

  • Symbol.for(key): 根据指定的键key,从symbol 注册表找到对应的symbol。找到则返回,否则创建一个与该建关联的symbol, 并放入全局的注册表中。

image.png

tips:

  • 在创建 Symbol() ,做唯一值的时候,传入的参数,仅仅是一个描述。

  • 当全局共享,使用Symbol.for(), 传入的参数,是一个关键key。用于查找是否存在对应关系

对 symbol 使用 typeof 运算符

symbol 作为基本数据类型,用typeof 就可以轻松识别类型

typeof Symbol() === 'symbol' // true
typeof Symbol('描述') === 'symbol' //true

symbol 作为基本数据类型,他和Symbol()的关系是什么呢?🤔

image.png

从上图可以看出,Symbol是一个函数,那Symbol() 就是调用Symbol函数,返回了一个symbol 类型的值,并且这个值是唯一的,有兴趣可以看这里

developer.mozilla.org/zh-CN/docs/…

Symbol 类型转换

符号在类型转换时表现得并不灵活,它无法与数字或字符串进行运算,也无法显式的转换成数字。如下所示,后面四条语句在执行时都会报错。

let sym = Symbol("age");
Number(sym);
parseInt(sym);
1 + sym;
"" + sym;

不过,符号可以显式的转换成字符串或布尔值,具体如下所示。

Boolean(sym);      //true
!sym;              //false
sym.toString();     //"Symbol(age)"
String(sym);        //"Symbol(age)"

Symbol 与 JSON.stringify()

当使用 JSON.stringify() 时,以 symbol 值作为键的属性会被完全忽略:

JSON.stringify({[Symbol("foo")]: "foo"});
// '{}'

Symbol 与 for...in 迭代

如果使用Symol(),作为一个对象的属性,我们该怎么用,迭代Symbol(),会有什么不一样吗?🤔

  1. 在对象中,Symbol()作为属性,需要 [] ,这不是代表数组,只是一个约定

image.png

  1. 使用for in 做循环

image.png

使用for...in 循环并没有将Symbol()属性遍历出来,那该怎么遍历对象里的所有属性呢(对属性做检索)?

  1. 获取对象Symbol类型的私有属性Object.getOwnPropertySymbols
console.log(Object.getOwnPropertySymbols(obj)); 

image.png

  1. 获取对象所有类型的属性Reflect.ownKeys
console.log(Reflect.ownKeys(obj));

image.png

Symbol.for() 的迭代

除了自己创建的 symbol,JavaScript 还内建了一些在 ECMAScript 5 之前没有暴露给开发者的 symbol,它们代表了内部语言行为 - 内置符号。我们看一下有哪些

image.png

我们使用 Symbol.for(key)做全局共享,自然也可以用,Symbol.keyFor(key) 做迭代

// 创建一个全局 Symbol
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"

var localSym = Symbol();
Symbol.keyFor(localSym); // undefined,

// 以下 Symbol 不是保存在全局 Symbol 注册表中
Symbol.keyFor(Symbol.iterator) // undefined

Symbol的内置符号

除了自己创建的 symbol

egg: Symbol() 做原始值,确保唯一性

JavaScript 还内建了一些在 ECMAScript 5 之前没有暴露给开发者的 symbol,它们代表了内部语言行为,也叫做知名符号(Well-Known Symbol)。它们可以使用以下属性访问

image.png

这些方法的重要性,不言而喻,比如我们经常用

for... of 迭代

image.png

数组解构

image.png

他们的原理都是 通过 Symbol.iterator 实现的 那如果我想用for... of 迭代对象呢🤔

image.png

对象不是可迭代的

我们来看一下对象原型和数组原型上对Symbol.iterator的存在

image.png

image.png

为什么这么多重要的重要的方法,属性要使用Symbol 防止重复声明和冲突,避免随意修改 image.png

下一次给大家聊聊,怎么自己实现一个Symbol.iterator,让我们的对象也用上for... of