说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

【探秘ES6】系列专栏(八):JS的第七种基本类型Symbols

HTML文档下载 WORD文档下载 PDF文档下载
新一代JavaScript标准ES6正式发布。【探秘ES6】系列专栏将一一剖析ES6的诸多新特性,让Web开发者对此有清晰全面的了解。本文为系列的第七篇,带你了解ES6的Symbols。

ES6作为新一代JavaScript标准,已正式与广大前端开发者见面。为了让大家对ES6的诸多新特性有更深入的了解,Mozilla Web开发者博客推出了《ES6 In Depth》系列文章。CSDN已获授权,将持续对该系列进行翻译,组织成【探秘ES6】系列专栏,供大家学习借鉴。本文为该系列的第八篇。 

本期我们要讨论的symbols是个什么东西呢?

这里的Symbols不是指的徽标。

也不是能在代码中使用的小图片。


它也不是代表其它任何东西的一个别名。

当然咯,Symbols和Cymbals(铜钹)完全是两回事。


(在编程过程中使用铜钹可不是一个好主意,吵到你炸!)

言归正传,什么是Symbols呢?

它是Javascript的第七种基本类型

自1997年Javascript被标准化以来,它定义了六种基本类型。直到ES6,JS程序中任何一个值都属于以下几种类型之一。

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Object

每种类型都是一系列值的集。前五个都是有限集。当然,Boolean类型只有true和false两个值,而且他们应该不会给Boolean型增加新值了。其它类型的值基本上都是数字和字符串。理论上说Numbers类型有18,437,736,874,454,810,627个值(包括了NaN,NaN是“Not a Number”的缩写)。String类型中可能的值就太多了,我算算大概有 (2144,115,188,075,855,872 − 1) ÷ 65,535个……当然,我这种算法不一定是精确的。

Object是一个无限集,每一个Object都是独一无二的。你随意打开一个Web页面就会生成一大堆新的Object。

ES6 Symbols也是一个集,但它的元素既不是字符串也不是对象。它是ES6的新成员:第七种基本类型。

让我们来谈谈它的应用场景。

以一个简单的布尔型来举例

在JavaScript中,有时候将一个对象中的数据扩展到其它某个对象中是十分方便的。

例如,假设你正在写一个JS库,目的是使用CSS过渡让DOM元素在屏幕上移动。你应该知道同时使用多个CSS过渡在同一个div上是行不通的。这会引起div不规律跳跃。你打算解决这个问题,不过首先你得想法知道这个元素是否正处在一个过渡中。

怎样来解决这个问题呢?

其中一种方式是使用CSS APIs让浏览器来告诉你元素是否在位移过程中。但这未免有点杀鸡用牛刀了。你的库应该存储了移动状态:代码中触发过渡的时候就应该记录了!

你真正需要的是一种方法来跟踪记录哪些元素在过渡。你可以把过渡中的元素存在一个数组中。每当你的库触发一个元素的过渡之前,先检测那个元素是否在数组中。

遗憾的是,如果数组很大的话,遍历起来会很耗时。

在你看来最简单的方法其实是为元素设置一个标识:

if (element.isMoving) {  smoothAnimations(element);}element.isMoving = true;

这样也会有一些潜在的问题。无法避免的事实是代码中会用到这个DOM的地方不止这一处。

  1. 其它代码中如果使用了for-in 或者 Object.keys()会遍历DOM的所有属性(会造成额外性能消耗)。
  2. 一些思维灵活的库作者会从技术方面考虑——你的库与其它库兼容性会很差。
  3. 一些思维灵活的库作者也会考虑扩展性——你的库扩展性也会很差。
  4. JS标准委员会将来也许会为所有元素提供一个.isMoving()的方法,那么你需要重构你的代码,那时候你就傻眼了。

当然,你可以用一个冗长或傻瓜式的字符串来作为属性名,只需确保不会和别的属性重名。

if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) {  smoothAnimations(element);}element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true;

代码写成这样也太虐待自己的眼睛了。

使用加密方法你可以生成一个理论上唯一的属性名:

// get 1024 Unicode characters of gibberishvar isMoving = SecureRandom.generateName();...if (element[isMoving]) {  smoothAnimations(element);}element[isMoving] = true;

object[name]语法使你可以使用任何字符串作为属性名。所以这样是可行的:不会有命名冲突,看起来还清爽!

但是,这样会导致调试体验糟透了?当你使用console.log()来打印元素的这个属性时,你会看到一大段字符串的垃圾数据。并且,这样的属性不止一个吧?你将如何保持连续性?每次重新加载的时候它们都生成不同的属性名。

为什么要搞得这么复杂?我们要得仅仅是一个简单的布尔值而已!

Symbols可以解决这个问题

Symbols集中的值可以由程序创建和并作为属性的键来使用,也不用担心名称冲突。

var mySymbol = Symbol();

调用Symbol()来创建一个新的Symbol值,它不会等同于其他值。

与字符串和数字一样,你可以使用symbol来作为属性值。因为它不等同于其它任何字符串,这个symbol-keyed属性可以确保不会与其它任何属性冲突。

obj[mySymbol] = "ok!";  // guaranteed not to collideconsole.log(obj[mySymbol]);  // ok!

接下来这方法就可以解决上面我们所讨论的那种情况:

// create a unique symbolvar isMoving = Symbol("isMoving");...if (element[isMoving]) {  smoothAnimations(element);}element[isMoving] = true;

关于这段代码的几个说明:

  • Symbol(“isMoving”)中的“isMoving”被称作描述。它对调试很有用。当你使用console.log()就可以打印出对应的symbol值,如果你想把它转换为字符串(比如说在打印错误信息的时候)可以使用.toString()。
  • element[isMoving]被称作symbol-keyed属性(使用symbol作为键的属性)。从字面意思就可以说明它就是使用symbol作为属性名而不是使用字符串。除去这一点,它和其它属性并没什么区别。
  • 和数组元素一样,symbol-keyed属性不能通过圆点符号来获取值(obj.name 这样是不行的)。它的值必须通过方括号来获取。
  • 通过symbol的值获取symbol-keyed属性值就很容易了。上面的例子展示了如何获取和设置element[isMoving],我们可以判断元素的isMoving状态了,如果有必要的话甚至可以删除isMoving状态。
  • 另一方面,以上的前提是isMoving在当前作用域中。这体现了symbols的弱封装机制:一个模块可以创建几个symbols在对象中任意使用而不用担心与其它模块的属性冲突。

因为symbol键值是被设计来避免冲突的,所以JavaScript最基本的对象检测特性是会忽略symbol键值的。以for-in循环为例,循环只会遍历对象的字符串类型的键。Symbol键直接被忽略过了。Object.key(obj)和 Object.getOwnPropertyNames(obj) 也是这样运作的。但是sysmbols并不完全是私有的:可以使用新API——Object.getOwnPropertySymbols(obj)将所对象的所有symbol键;另一个新API—— Reflect.ownKeys(obj),将会同时返回string和symbol类型的键。(在以后的文章中我们将完整地探讨Reflect API。)

在库和框架中symbols将会有很多用途,不久我们会看到,JS语言本身对它也会有广泛的使用。

symbols确切定义是什么呢?

> typeof Symbol()"symbol"

Symbols和其它基本类型大不一样。

从创建开始就是不可变的。你不能为它设置属性(如果你在严谨模式下尝试,会报类型错误)。它可以作为属性名。这是它的类字符串性质。

另一方面,每一个symbol都是唯一的。与其他的不同(就算他们的描述是一样的)你可以很容易地新创建一个。这是它的类对象性质。

ES6 symbols与Lisp和Ruby中的更传统的symbols很类似,但是没有如此紧密地集成到语言中。在Lisp中,所有的标识符都是symbols。在JS中,标识符和大多数属性的键值的首先仍是字符串,Symbols只是为开发人员提供了一个额外选择。

关于symbols的一个忠告:与JS中的其它类型不同,它不能被自动转换为字符串。试图拼接symbol与字符串将会引起类型错误。

> var sym = Symbol("<3");> "your symbol is " + sym// TypeError: can't convert symbol to string> `your symbol is ${sym}`// TypeError: can't convert symbol to string

你可以通过显示地将symbol转换为一个字符串来避免这个问题,通过String(sym)或者sym.toString()。

symbols的三种形式

有三种方法来获取symbol。

  • Call Symbol()。我们已经讨论过这种方法了,每一次调用它都将返回一个唯一的symbol。
  • Call Symbol.for(string)。这种方法访问一组已经存在的symbol注册表。与通过Symbol()来定一个唯一值不同的是,symbol注册表中的symbols是共享的。如果你调用Symbol.for(“cat”)三十次,每一次返回都将是同一个symbol。在多页面或者单页面的多模块需要共享symbol时,这是很有效的方法。
  • 使用标准中定义的Symbol.iterator。标准委员会自己定义了几种symbols。每一种都有它的特殊意义。

如果你仍然不确定symbols是否对你有帮助,这最后一个章节会很有趣,因为证实了在实践中symbols是很有用的。

ES6的文档中对通用symbols的使用是如何介绍的?

我们已经看过了ES6是如何使用symbol来避免与已有代码命名冲突的。几周前,在关于迭代器的文章中,我们了解了循环(var item of myArray)是从调用myArray[Symbol.iterator]()开始的。我提到这个方法以前的写法是myArray.iterator(),但是加了symbol以后向后兼容性会更好。

现在我们知道了symbols的用法和作用。那么就很容易理解为什么这样做和这样做的意义是什么。

这里还有其它几个ES6使用通用symbols的场景。(这些特性在Firefox中还没实现。)

  • 使instanceof可扩展。在ES6中,表达式object instanceof constructor被指定为构造函数的一个方法:constructor[Symbol.hasInstance](Object)。这表明它是可扩展的。
  • 消除新特性和旧代码之间的冲突。这比较难理解,但我们发现一些ES6的数组方法将会破坏旧网站的稳定性。其它的Web标准也会有类似的问题:仅仅是添加新方法到浏览器中,已存在的网站就会受到影响。无论如何,造成这些不稳定性的主要原因主要是由动态作用域引起的。所以ES6引入了一个特殊的symbol——Symbol.unscopables,这个Web标准可以用来防止某些方法被牵连到动态域中。
  • 支持新的字符串匹配。在ES5中,str.match(myObject)尝试将myObject转换为正则表达式对象。在ES6中,首先检查myObject是否有myObject[Symbol.match](str)方法。现在库就可以给任何有正则表达式对象的地方提供通用的解析类。

所讲到的这几个symbol的应用都不常见,很难看到这些特性本身对我们的日常代码有任何影响。从长远看就比较有意义了。通用symbols是JavaScript对于PHP和Python中的__doubleUnderscores的改进。标准委员会将来会添加新的hooks到JS中,而不会有影响已有代码的风险。

我什么时候可以开始使用ES6 symbols?

Firefox 36和Chrome 38已经支持Symbols了。我自己也在Firefox中试过了,如果你运行的时候有问题,你该知道问谁吧——找我!

为了让那些本身还不支持ES6 symbols的浏览器支持它,你可以使用pollyfill(一段代码或插件,提供了那些开发者们希望浏览器原生提供支持的功能),比如core.js。因为Symbols还比较新,所以它的pollyfill还不是那么完善,详细了解请看使用说明。

接下来的两篇博客,首先会讨论一些我们期待已久的特性终于被ES6支持了,我实在忍不住抱怨它们的姗姗来迟。我们将从两个很古老的特性作为开始(老到几乎可以追溯到编程历史的起源),紧接着讨论两个与之非常相似的特性,由ephemerons提供技术支持。下次还将深入讨论collections(集合)。

原文链接:ES6 In Depth: Symbols

本译文遵循Creative Commons Attribution Share-Alike License v3.0 

相关阅读:

【探秘ES6】系列专栏(一):ES6简介

【探秘ES6】系列专栏(二):迭代器和for-of循环

【探秘ES6】系列专栏(三):生成器

【探秘ES6】系列专栏(四):模版字符串

【探秘ES6】系列专栏(五):剩余参数和默认参数

【探秘ES6】系列专栏(六):解构赋值

【探秘ES6】系列专栏(七):箭头函数

欢迎加入CSDN前端交流群:218126086,进行前端技术交流。  

福利来了,爱拍原创免费为iOS版手游制作宣传视频 【工具推荐】Zrender——轻量级Canvas类库,让绘图大不同! 基于Docker和CoreOS的开源PaaS平台——Deis v1.0正式发布! 微软宣布.NET开发环境开源 支持三大操作系统 爆发吧,诺基亚!前员工开发物联网新设备 详解Visual Studio Emulator for Android,微软的Mobile First! HPC China 2014完美落幕,AMD Firepro荣获好评! 揭秘微软的Container技术之一Drawbridge AWS副总裁谈数据中心网络打造 【最具价值CTO评选秀】出门问问CTO雷欣:从技术极客到核心管理的秘密 《近匠》APICloud:“云”+“端”一体的移动API提供者 Oculus移动SDK发布!John Carmack操刀、集成Unity 4.5 11月15日深圳见!深圳微信开发者大会公布全部议程 参与2014中国大数据行业大调查 BDTC门票等你拿 HTML5规范尘埃落定,5个开发工具推荐 盘点最受开发者喜爱的Android 5.0 Lollipop API IoE Day侧记:想开发智能硬件?先要弄明白这几个问题 【问底】许鹏:使用Spark+Cassandra打造高性能数据分析平台(二) 微软承诺所有Lumia WP8设备将升级至Win10,用户会买账吗? 周末,深圳微信开发者大会等您来!(参会必读+名单) 营造云安全生态链 第五届云安全联盟高峰论坛在京顺利召开 中国大数据六大技术变迁记 【最具价值CTO评选秀】当当网CTO熊长青:结合行业及技术发展,规划技术方向 社交颠覆传统,环信技术交流沙龙纪实(组图) 揭秘经典案例炼成之道 微信开发者大会精华回顾 从一家电子商务网站学到的经验教训 【最具价值CTO评选秀】极路由CTO康晓宁:极客转型CTO的感悟 盘点这些年来的“微信万能论” 《近匠》亲加通讯云:IM即时通讯API的极致服务者 TCL杯HTML5智能电视开发大赛完美落幕,8项获奖应用大揭晓! Xcode 6.2 Beta发布,支持WatchKit的iOS 8.2 SDK来了! 【急】如何处理一组RadioButtonList呢? 签名活动:目前csdn里面发现很多作弊者,反对作弊者进来签名! 哪有中文MSDN下载?先谢谢 请帮忙看一下这个setfilter应怎样写? (这个问题,不会没有人不知道!)关于vfp6统计图的问题`~急呀`~救命呀`~~~回答者都给分`~~ 打印预览窗口的显示问题 vb中的trim在c# 中如何表达 数据库 我为中国队加油,看看我的为中国队加油首页! 关于FLASH的??<在线等待> 请教各位大虾!!!急,我的分数全部送出!!! 高手们怎么样才能在窗体上引入FLASH动画呀????? 好烦啊!oracle 7.3.4数据导到oracle9i的字符集问题 每当我最困难的时候,我就想起了csdn,50分奉送!!!!!图像问题 QuickReport设置的问题 如何打印源代码! 那位大虾知道ACTIVEX命名的由来 请问什么错误,在brinkster测试通过,但是放在另外的站点,却不行了。 中国必胜 mfc 中的类型是怎么定义出来的(比如 dword,LPTSTR 等) 救急!!关于表单中文件域的使用。 奇怪的问题!!!!! 请问什么是contentPane? 用Delphi作网页用IE浏览不行 求助:AfxBeginThread的编译问题! 用C裸写聊天软件,谁能? 菜鸟问题:如何安装和配置ASP.NET开发和运行环境? 快来呀,破解QQ密码,高分相送! 有需要域名和空间的吗?我这里有。 我的服务器CPU占有100%,如何解决?!!加急!!!!!! 请问谁在csdn上订购过书啊?需要多少时间才能拿到啊!!!! 小问题:关于AfxBeginThread的参数调用问题 请教高手:关于在ACCESS中的两个数据库之间复制表结构问题 请问谁在csdn上订购过书啊?需要多少时间才能拿到啊!!!! 问题求解 现实一点,各位,我和别人赌了巴西不能赢中国队净3球以上,大家如何看? datagrid连接adodc access转化为mssql时出现的一些问题??? 工作流运行时出现了问题!很奇怪! 一个注册表的问题? 关于STL的弱问题 很少有人问的问题 请教学习路线,散分 一个困扰我很久的难题?(高手帮忙啊) 告诉帮我解决文件关联问题!! 请问如何添加备注字段,用sql server建表,有一备注字段为text类型。。。。。。。。。。。 函數啊﹐怎么么搞的?氣死人了。一百求救。 关于数据库的问题 生命游戏问题!!!!那位大哥指点迷津 VB做的免费软件,大家随便下载!给我提点建议也行! RichEdit问题,急!!! 如何配平氧化亚铜与氧气在加热条件下反应生成氧化铜 6.强酸与强碱的稀溶液发生中和反应的热效应为:H+(aq)+OH-(aq)=H2O(l)△H=-57.3KJ•mol-1.分别向1L 0.5mol•L-1的Ba(OH)2的溶液中加入①浓硫酸;②稀硫酸;③稀硝酸,恰好 氨水含煤粉适合用什么泵,现在用的是多级屏蔽泵,老坏,扬程230m,流量16立/小时温度90℃ H2O和Na2O2反应,为什么转移2e-个电子 只有强酸强碱才能发生中和反应吗? 我是工程的设计,我不了解屏蔽泵,想知道屏蔽泵的结构是什么样的? 电流的磁效应 电生磁 磁生电 磁体在磁场受力的作用的区分 中和热一定是强酸和强碱反应吗 铝离子和亚硫酸根双水解吗、、? 常见的强酸弱酸与强碱弱碱有哪些? 岛津高效液相色谱仪,在出主峰时,主峰峰尾处有个连接着的小包.请问这是什么原因呢?顺便说下如何解决,如何判断. 关于铝离子的水解,困扰了好久假如有1mol铝离子,我想让他完全沉淀,写出方程式,应该加3mol氢氧化钠(或者更少 避免生成的沉淀水解)但是利用水解方面的知识,调ph值,完全沉淀ph4~10多(具体 怎么区分电流磁效应,电磁感应,电生磁,磁生电,通电线圈受力作用的这些实验啊 乙腈在气相色谱上能出峰吗?我用的气相色谱,进了针纯品,没峰,乙腈在气相上有峰吗?应该用什么柱子?条件是什么? 硝酸和异丙醇会发生什么反应? 电生磁就是电流的磁效应就是奥斯特实验吗 电磁感应现象是否就是磁生电? 异丙醇中毒的症状是什么 为什么电解水后生成气体的比是体积比2:1?为什么是体积比?而不是质量比.等 其他的是不是所有原子的体积都一样? 磁单极子穿过超导线圈的过程中,线圈内产生不断增强的电流.请问为什么?为什么磁单极的磁通量变化率...磁单极子穿过超导线圈的过程中,线圈内产生不断增强的电流.请问为什么?为什么磁单 为什么能发生碘仿反应就推出它是异丙醇啊 电解水实验中气体体积比大于2:1的两个原因两个原因,简短点 【化学】关于苯酚钠溶液和二氧化碳的反应苯酚钠和二氧化碳反应后溶液变浑浊,请问:沉淀是苯酚还是碳酸氢钠?碳酸氢钠在水中的溶解度很小有方程为正Na2CO3(饱和)+H2O+CO2=2NaHCO3所以才问是 异丙醇铝能用异丙醇和铝直接反应么快,谢了 电解水试验中气体体积比常大于2:1,可能原因是 乙酸与邻羟基苯甲酸反应生成的化合物怎么命名?(反应能否进行先不论) 是乙酸邻苯甲酸酯吗?反应能否进行先不论,就是羟基和乙酸脱水后,生成的产物.是乙酸邻苯甲酸酯吗? 求扩散是什么意思 苯与液溴反应,稀苯酚溶液与浓溴水反应;区别? 电解水产生的气体体积为什么为2比1 鉴别对氨基苯甲酸,邻羟基苯甲酸,对甲基苯甲酸 醋酸铵会双水解,为什么醋酸根与铵根可以共存ghx0305172那铵根还是变成一水和氨,不就不能共存了 原始大气成分与现代大气相同.这句话对吗?这是我看到中考考试要求里的一道题才有的疑问。下面是原题及讲解。13、下列关于生命起源和生物进化的叙述中,错误的是………………………… 四川地震生命的奇迹最长多少小时,我看到了160多小时的,还有比他更坚强的吗?具体一点, 醋酸根离子与铵根离子为什么在溶液中能大量共存? 地质学表明,原始大气成分于现在大气相比的的明显差别是什么?A,氧气B,氢气C,水蒸气D,甲烷 电磁感应现象是磁生电还是电生磁 铵根和醋酸根可以双水解吗? t摄氏度时,将一定量的KNO3的不饱和溶液平均分为三份,分别恒温蒸发出水的质量为5g、10gt摄氏度时,将一定量的KNO3的不饱和溶液平均分为三份,分别恒温蒸发出水的质量为5g、10g、15g,析出KNO3晶 流量变化与水泵功率变化是什么关系一自吸泵,出水端有一蝶阀 其他条件不做任何改变 只是调整蝶阀开启的大小控制出水流量大小 请问流量增大 水泵实际功率怎么变化 还有如果蝶阀完全关 锌铜原电池,稀硫酸作电解质,铜片的质量是逐渐减少吗 氢离子和钾离子氯离子铝离子亚硫酸根离子的混合溶液为什么不共存? 汶川地震中坚持时间最长的幸存者崔昌会,在废墟下靠蚯蚓和野草为食,最终创造了生命的奇迹.用不同表达方式改写这句话,要求句子的意思不变 磁单极子从上往下穿过超导线圈的过程中,线圈内产生不断增强的电流.请问为什么?磁单极子穿过线圈进入到线圈下方时磁感线不是向上透过线圈了吗 为什么电解水刚开始时气体体积之比不是2: 亚硫酸铝 如果一个只有N极的磁单极子从上至下穿过如图所示的超导线圈那么从上往下看,超导线圈将出现怎样的电流情况我认为根据楞次定律当带有N的磁单极子向下运动时对于线圈N极所影响变大然后 电解水实验刚开始时两管气体的体积不符合理论比的原因正常进行的实验 为什么屏蔽泵出口压力大时电流会小 一个只有N极的磁单极子从上向下穿过一个超导线圈,从上往下看超导线圈的感应电流方向是怎样的? 在真空中,一半径为R的圆形线圈通以电流I,在其圆心处产生的磁感应强度大小为_______,该线圈的磁矩大小为_______. 铝离子与亚硫酸根的完全双水解的离子反应? 只有一个磁极的磁单极子A通过一超导材料制成的线圈,A离开线圈后电流怎么变化?题目的意思就是假设它已经存在了,答案选的是A离开线圈后,电流保持不变, 实线圆环A、B是光滑绝缘水平面内两个固定的同心超导环,两环分别通上大小相等的电流后,在如图所示,实线圆环A、B是光滑绝缘水平面内两个固定的同心超导环,两环分别通上大小相等的电流 非屏蔽泵与屏蔽泵的工作原理有何不一样.他们分别适用哪些种场合.非屏蔽泵与屏蔽泵使用于哪些场合呢. 1 mol Na2O2与1 mol H2O反应,转移电子是多少mol为什么 圆环上的线圈通以如图所示的电流,则在圆环的圆心O处的磁场方向为解析:由安培定则知螺线管上端为S极,下端为N极,两个螺线管在O点磁场方向均向上,合磁场方向仍向上,故A选项正确. 为什么 亚硫酸铝溶液能稳定存在么是不是发生双水解 na202与h2o反应转移了多少mol电子? 强酸与强碱的稀溶液发生中和反应的热效应:H离子+氢氧根离子==H2O △H=-57.3kJ/mol,向0.5mol的NaOH溶液中加入稀醋酸,浓硫酸,稀硝酸,则恰好完全反应的热效应△H1,△H2,H3的关系是?(由小到大) 什么是屏蔽泵?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘