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(符号).符号可以像字符串那样作为对象的属性名,只是他有唯一性,可以避免属性名之间的冲突
Symbol( [description] )
- 每个从
Symbol()返回的 symbol 值都是唯一的
- 我们可以写无数个 Symbol()他们都是唯一的,但是怎么去区分呢🤔,可以添加一个
description。这仅仅是描述,并不能以此来访问 symbol 本身
- 原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持。 然而,现有的原始包装器对象,如
new Boolean、new String以及new Number,因为遗留原因仍可被创建。 对于ES6中新增的另一种数据类型bigint呢? 也是一样滴 😄
如果真的想创建一个 Symbol 包装器对象,可以使用 Object() 函数
每个从 Symbol() 返回的 symbol 值都是唯一的。但是如果想共享值呢?🤔 要共享的值要用Symbol.for()
- Symbol.for(key): 根据指定的键
key,从symbol 注册表找到对应的symbol。找到则返回,否则创建一个与该建关联的symbol, 并放入全局的注册表中。
tips:
-
在创建 Symbol() ,做唯一值的时候,传入的参数,仅仅是一个描述。
-
当全局共享,使用
Symbol.for(), 传入的参数,是一个关键key。用于查找是否存在对应关系
对 symbol 使用 typeof 运算符
symbol 作为基本数据类型,用typeof 就可以轻松识别类型
typeof Symbol() === 'symbol' // true
typeof Symbol('描述') === 'symbol' //true
symbol 作为基本数据类型,他和Symbol()的关系是什么呢?🤔
从上图可以看出,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(),会有什么不一样吗?🤔
- 在对象中,Symbol()作为属性,需要 [] ,这不是代表数组,只是一个约定
- 使用for in 做循环
使用for...in 循环并没有将Symbol()属性遍历出来,那该怎么遍历对象里的所有属性呢(对属性做检索)?
- 获取对象Symbol类型的私有属性
Object.getOwnPropertySymbols
console.log(Object.getOwnPropertySymbols(obj));
- 获取对象所有类型的属性
Reflect.ownKeys
console.log(Reflect.ownKeys(obj));
Symbol.for() 的迭代
除了自己创建的 symbol,JavaScript 还内建了一些在 ECMAScript 5 之前没有暴露给开发者的 symbol,它们代表了内部语言行为 - 内置符号。我们看一下有哪些
我们使用 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)。它们可以使用以下属性访问
这些方法的重要性,不言而喻,比如我们经常用
for... of 迭代
数组解构
他们的原理都是 通过 Symbol.iterator 实现的
那如果我想用for... of 迭代对象呢🤔
对象不是可迭代的
我们来看一下对象原型和数组原型上对Symbol.iterator的存在
为什么这么多重要的重要的方法,属性要使用Symbol 防止重复声明和冲突,避免随意修改
下一次给大家聊聊,怎么自己实现一个Symbol.iterator,让我们的对象也用上for... of