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

【探秘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,进行前端技术交流。  

未来程序员会被机器取代吗? React Native实战(一):配置和起步 集聚MDCC 2015 免费展位第二波正式放出 【深入浅出Koa】入门知识,带你以现代化开发方式构建Web应用 升级到Node V4的七个理由 支持大量ES6特性 像写SQL一样编写Java数据应用 Swift 2.0实战:如何实现从非零下标遍历数组? 手把手教学:在iOS 8中使用Cocoapods 交互技术前沿与应用实战:MDCC虚拟现实专场议程揭晓 解密“攻城狮使用手册” 技术专家齐聚!MDCC 2015精彩日程全曝光 基于ActiveMQ的消息中间件系统 OneMM逻辑与物理架构设计详解 John Carmack大神亲操刀,为Oculus开发Netflix应用 React Native实战(二):Android的打包 独立游戏的成功秘诀:好设计才是王道 Swift 2.1的新变化 Apple TV实战:用TVML开发第一款tvOS应用 【SDCC讲师专访】阿里王晶昱:云时代的分布式数据库DRDS 硬件研发、嵌入式技术演进:MDCC IoT峰会日程揭晓 专访百度知道iOS团队负责人孙源:代码强迫症的死实践派 TIOBE 2015年10月编程语言排行榜:Ruby取代Objective-C进前十 【SDCC讲师专访】PingCAP联合创始人兼CEO刘奇:好的产品应开源,不闭门造车 【深入浅出Koa】常用工具分享 帮你降低编程难度 Relay: 全新的React数据获取框架 探索游戏开发面临的技术挑战——MDCC 2015游戏开发专场议程曝光 【SDCC讲师专访】易开发创始人潘俊勇:这些年我遇到的那些坑 【CTO讲堂】OpenStack行业实践和发展趋势探讨 万物互联,移动为先:MDCC 2015移动开发者大会盛大开幕! 【MDCC 2015】微软开发体验与平台事业合作部大中华区DX部门总经理Srikanth Raju:物联之上云+端 英雄会晚宴,Top开发者共聚“华山之巅” 【MDCC 2015】产品与设计专场(上):百度研究院、印象笔记等专家齐聚,以实例探讨如何打造好产品 ActiveX访问数据库的问题? REDHAT LINUX 7.2下如何建立多个用户?多谢指点! 关于网线!高分!!!!! 关于生成文件的方法? 课程表开发 请问各位前辈,是否只有新增加的字段才有可能成为计算字段?谢谢! 俺要写一个简单的文本的报文,string类型的 关于生成文件的方法?..... 有谁能告诉一下我CVS和SSF是什么?,具体是指些什么?? WIN2K 的问题:1、怎么允许本地普通用户(user)关机;2、怎么能让本地普通用户开机后,客户机连接到SQL SERVER?3、为什么我的SQL量SERVER2K需要停止然后再启动客户才能用? 如何用VB把存储在ORACLE库中的图片字段取出成.JPG格式的图片文件????急在外出差呀多谢了~~~~~ 如何退出函数?exit function??? 测试2000的TCP/IP是否通,用什么命令 求助开发课程表提示 (*****向斑竹你提个小见意,大家最好都来看看,这个想法好不好!****) 为什么我做的增加功能有两个必须要按两次“添加”按钮才能新增一条记录啊? 很急,请教高手,如何把一个ip格式的字符串转换成ip类型,不是用getbyname(),而是像int和string转换一样的概念 请问如何让基于对话框的工具条一开始就浮在上面 来者有分,关于ado的 毛子青论文<<动态规划的优化>>,一个最长子序列的算法,请高手看过来(给出c实现代码的送20分!) 在鼠标单击时间中,可以使用什么函数取得鼠标点击处的坐标值 怎样在单击左键时弹出PopupMenu? 连续20多天加班,近来明显感到体力透支,做个调查!!!(有分) ASP调用VB编写的ActiveX DLL的问题 请教一sql语句 在Unix下用cc(实际上是cc_bundled文件)编译c程序时,报错“const" will become a keyword,或者告诉我“Function prototypes are an ANSI feature" 为何加入winsock2.h后会出现很多问题? 热烈庆祝:Kingron重出江湖!!!菜鸟们有福喽……散分 you shen me qu bie ? please tell me , xie xie ! [■■■Delphi猛料■■■]V1.3发布~~~~~~~更新到2001.12.12 提问:如何在ToolBar上加控件? 我在OLE里调用了word2000文档,为什么只显示第一页,我查了半天资料都没有解决,请帮我 哪里有多媒体软件制作论文啊? 继续请教各位前辈:能否将非新增加的字段定义成计算字段?谢谢! 软件创意、需求大汇集:列创意,拿专家分,120分值大赠送(以后可继续追加) 局渔网 巨简单问题~~~ 进来有分,回答多分,不够再加!!! 关于关闭和启动数据库的问题,很急的!! java VS c#^-^ ?? 请进 寻求QuickReport3以上版本 for Delphi3 的源代码或者安装包? 請問哪大俠用過 ibm 的 bridge2java啊,我把Excel的所有類都導出來了,但它的QuickExcel.java文件還是運行不了, 求救!新装了一块硬盘,为何找不到呀? SetWindowLong函数在delphi里可用,为什么在c++builder 中不能用??? 用弹出式菜单命令弹出一个dialog,可以响应键盘,可是不响应鼠标? 请教,Inserts类是拿来干什么用的? !!!急急急!!!怎样在WIN2000下把NTFS转换成FAT32啊。数据不丢失。 回复太短!或太长!!! visio2002的数据库建模,能不能生成SQL脚本? 急急啊,有關servlet的問題,源碼如下: 添加数据的问题 坐标问题 无铅波峰焊锡炉焊锡温度是我多少?预热温度是我多少? 焊锡大多是63%锡的,另外37是什么?铅是有毒的啊!吸入焊锡发出的烟会不会中毒啊?市场上无铅焊锡很少啊!另外松香怎么用,用100%酒精混合使用? 海水可以结冰么?不可以,因为大海里的水含有盐分,有盐的东西都不会结冰的. 在雪地上撒盐后雪的温度如何变化?为什么?各位好心的前辈,学妹我刚步入初三,请你们看清我的题目要求,我只想知道在雪地上撒盐后雪的温度如何变化,极其原因.至于为什么撒盐我已经弄清 哪里有卖无铅焊锡丝和吸锡线的?最好在小白楼附近,别的地方也行.大概什么价钱?吸锡线一定要小日本的,没办法质量好. 海水结冰温度是多少? 焊锡材料方面问题,无铅焊锡中的Sn-3Ag,锡占多少比例,银占多少比例? 海水结成的冰是咸的马? 海水结冰问题冻牛奶时,冰和奶是分开的 冻豆腐会留下空室海水结冰盐会留在里面吗 在雪地上,为什么撒上盐雪就化得快 海水结的冰是咸的吗? 关于海水结冰问题海面上的水结冰,结成的冰融化后与没有结成冰的水的含盐量大概是多少比多少,如果给出各是百分之几更好.还有把海水晒成盐这种工艺叫做海水什么? 沸腾的液体是什么液体? 设计实验验证海水结的冰是淡的还是咸的.海水是淡的还是咸的,请利用厨房里的物品,设计实验模拟海洋环境制作“海冰”、并设计实验证明海冰是咸的还是淡的,要实验具体步骤。 中国那些地区海水结冰了? 液体沸腾的条件是什么 为什么海水是咸的.而海上的冰却是淡的? 海水易结冰还是河水易结冰? 饮料冰冻之后再冷藏味道淡了.能喝吗、 海水为什么这么咸?南北极的冰是不是"咸冰"?这么咸对人类有什么好处?真的没想到,我第一次下海,就是这样的感觉.海水太咸.所以想到了这些. 家庭和实验室常用的温度计是根据什么的规律来测量的 为什么饮料冻成冰之后味道会变淡比如说牛奶、橙汁之类的 为什么海水不结冰呢? 固体密度大概是液体密度的多少倍? 怎样快速冰冻汽水越快越好啦 怎么提纯焊锡中的锡?在家搞实验. 固体密度大于液体密度? 汽水会结冰吗如题那会不会爆炸 如何从助焊锡中提取焊锡 河水和海水哪个更容易结冰 锡焊的锡有几种状态(比如焊锡丝、焊条)? 海是河流汇聚而成的,还又流道各个河流,为什么海水是咸的,而河水是淡的?为什么呢? 为什么海水比河水难结冰 压力表锡焊用焊锡量多少的焊锡丝 为什么海水会又原先的淡变咸 怎么样求固体,液体的密度用五种方法测量物体的密度,方法越多越好。、文字说明,最好有图画,要讲清楚,不能有遗漏, 如何在焊锡丝中分离出纯锡 为什么海水咸,河水不咸 540kg的水化成冰 体积是多少 焊锡丝焊接时为什么锡会飞溅 为什么海水是咸的而河水、湖水是淡的呢? 1kg的水化成冰它的质量、体积分别是多少? 液体沸腾的两个条件是: 海水为何是咸的 甲乙两木块的质量比为3:2,其体积比为1:2,则其密度比为多少? 液体沸腾的条件 金属温度计\电子温度计的原理 甲乙两质量分布均匀的物体的体积相同,它们的质量之比是5:3,则它们的密度之比是_________.若甲截去3/5, 2008初我国大部分地区继续降雪,形成灾害性天气,人们往冰冻的路面上撒盐.这样做的目的是什麽? 海水为什么不会结冰? 温度计的原理问一下温度及时利用什么原理制作的?温度计的刻度是怎么画的?每一度之间的刻度是怎样计算的?为什么温度计选择酒精而不选择别的液体?是因为酒精防冻吗?希望可以说的详细 温度计的构造____ _____ _____ ______ 及_______ 焊锡是锡铅合金,把铅加入锡中制成合金的主要目的是增加强度和抗腐蚀性生铁和钢是含碳量不同的铁合金,其中生铁的含碳量大于钢的含碳量这两句话 哪句对? 温度计的原理是什么? 温度计的分类和作用 制造焊锡时把铅加进锡中的重要原因 海水会不会结冰?如果不会结冰那为什么南极和北极会结冰? 锡铜合金,即平常所见的焊锡,其中的铜起到什么作用呢? 制造焊锡时,把铅加入锡的主要原因 海水为什么不会结冰吗?
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn