ES6 Symbol之浅入解读????

栏目: JavaScript · 发布时间: 5年前

内容简介:这些描述几乎完全说明了这个新来的数据类型的用途:作为一个对象或一个Map的键值,他可以保证你的对象或Map的键值不重复(这个在某些场景下真的非常有用)。

Symbol 是ES6新增的数据类型,是一种基础数据类型,MDN 中的对Symbol类型的描述为: 数据类型 “symbol” 是一种原始数据类型,该类型的性质在于这个类型的值可以用来创建匿名的对象属性。该数据类型通常被用作一个对象属性的键值——当你想让它是私有的时候。

symbol 数据类型具有非常明确的目的,并且因为其功能性单一的优点而突出;一个 symbol 实例可以被赋值到一个左值变量,还可以通过标识符检查类型,这就是它的全部特性。

这些描述几乎完全说明了这个新来的数据类型的用途:作为一个对象或一个Map的键值,他可以保证你的对象或Map的键值不重复(这个在某些场景下真的非常有用)。 这个数据类型因为是ES6新增的,所以不存在polyfill。

二、用法

1. 对象

1.1 普通用法

能够用来创建 Symbol 的是一个像类的函数 Symbol() ,用来创建 symbol 数据类型实例。注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。【此处引用阮一峰老师在ES6教程里面的话】MDN上的解释是: 一个具有数据类型 “symbol” 的值可以被称为 “符号类型值”。在 JavaScript 运行时环境中,一个符号类型值可以通过调用函数 Symbol() 创建,这个函数动态地生成了一个匿名,唯一的值。Symbol类型唯一合理的用法是用变量存储 symbol的值,然后使用存储的值创建对象属性。 最简单的作为对象的key的写法如下:

var  privateKey  = Symbol();
var obj = {
    [privateKey] : 'hero'
}
//访问时
obj[privateKey]  //hero
复制代码

一般在键值对对象中我们访问某个属性的时候常用 . 符号来取到对应的值,但是用 . 符号去取值时, . 后面一定是一个字符串,因为ES6之前对象的key必须是字符串,所以当访问以Symbol实例为key时需要使用 [] 来包裹起来 (ES6同时增加了两种数据结构Set和Map,Map在某种意义上来讲,更加适合用来保存键值对的形式的数据,可以参照 Java 的Map的数据结构)。

var identity = Symbol()
var obj = {
    name : 'john',
    [identity] : 'hero'
}
obj.name   //'john'
obj[name]  //'john'
obj.identity   //undefined
//当我们使用.来访问时,因为不存在这个key,所以就会返回undefined,也符合上方所写的
obj[identity]  //'hero'
复制代码

1.2 遍历含有Symbol的对象

但是我们在遍历某个对象时,使用for in或for of方法时,Symbol为key或value时是不会出现在遍历结果里的;同样也不会被 Object.keys()Object.getOwnPropertyNames()JSON.stringify() 返回。但是伴随着Symbol一起出现的有一个方法可以取到它的值: Object.getOwnPropertySymbols ,可以获取指定对象的所有 Symbol 属性名。 Object.getOwnPropertySymbols 方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

const obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj[a] = 'Hello';
obj[b] = 'World';

const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols
// [Symbol(a), Symbol(b)]
复制代码

但是我们还有一个API可以用来将一个对象里面所有的键值全部反映出来,包含普通键和Symbol键: Reflect.ownKeys 。【参考自阮一峰的ES6教程】

let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};

Reflect.ownKeys(obj)
//  ["enum", "nonEnum", Symbol(my_key)]
复制代码

1.3 复用Symbol

Symbol虽然旨在给我们提供一个永远不会重复的特殊值,但是也确实会存在需要相同Symbol的场景,API永远比我们想得多,Symbol有一个方法: Symbol.for ,它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true
复制代码

这个API的工作原理大概流程是这样的:Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")30 次,会返回 30 个不同的 Symbol 值。【参考自阮一峰的ES6教程】 同样的, Symbol.keyFor 这个API可以返回一个已登记的 Symbol 类型值的key。

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
//因为s2不是以Symbol.for()创建的,所以使用Symbol.keyFor()无法得到其值
复制代码

2. 通用方法

当然,使用的时候为了更容易区分,一般而言我们会向Symbol()里面传递一个参数为了区分不同的Symbol,例如 Symbol('name') 这样,这样更有利于开发时进行调试

let symbol1 = Symbol('name');
let symbol12 = Symbol('age');

symbol1 // Symbol(name)
symbol2 // Symbol(age)
//上方的只是返回值而已,即使返回值相同,也不代表这两个Symbol相同!

symbol1.toString() // "Symbol(name)"
symbol2.toString() // "Symbol(age)"

//另外一个就是Symbol 值不能与其他类型的值进行运算,会报错。
Symbol('hero') + ' hello'  //TypeError: can't convert symbol to string
//如果真的要处理,我们只能先显式的将Symbol转化为字符串才能和其他数字或字符串相加
Symbol('hero').toString() + ' hello'     //hero hello
//Symbol可以转化为布尔值
Boolean(Symbol('hero'))     //true
//Symbol无法通过某种方式直接转化为数字
Number(Symbol('hero')) // TypeError
复制代码

三、结语

Symbol的出现目的很单一,就是作为对象的键值,常用的一些方法也非常好理解,关键是这个可以非常有效的消除magic string和magic number啊喂:joy:。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

黑客与画家

黑客与画家

[美] Paul Graham / 阮一峰 / 人民邮电出版社 / 2013-10 / 69.00元

本书是硅谷创业之父Paul Graham 的文集,主要介绍黑客即优秀程序员的爱好和动机,讨论黑客成长、黑客对世界的贡献以及编程语言和黑客工作方法等所有对计算机时代感兴趣的人的一些话题。书中的内容不但有助于了解计算机编程的本质、互联网行业的规则,还会帮助读者了解我们这个时代,迫使读者独立思考。 本书适合所有程序员和互联网创业者,也适合一切对计算机行业感兴趣的读者。一起来看看 《黑客与画家》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具