系列专栏(八):JS的第七种基本类型Symbols
cac55 2024-10-26 08:13 16 浏览 0 评论
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的地方不止这一处。
- 其它代码中如果使用了for-in 或者 Object.keys会遍历DOM的所有属性(会造成额外性能消耗)。
- 一些思维灵活的库作者会从技术方面考虑——你的库与其它库兼容性会很差。
- 一些思维灵活的库作者也会考虑扩展性——你的库扩展性也会很差。
- 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 gibberish var 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 collide console.log(obj[mySymbol]); // ok!
接下来这方法就可以解决上面我们所讨论的那种情况:
// create a unique symbol var 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(集合)。
本译文遵循Creative Commons Attribution Share-Alike License v3.0
相关推荐
- Mac电脑强制删除任何软件方法-含自启动应用
-
对于打工者来说,进入企业上班使用的电脑大概率是会被监控起来,比如各种流行的数据防泄漏DLP,奇安信天擎,甚至360安全卫士,这些安全软件你想卸载是非常困难的,甚至卸载后它自己又安装回来了,并且还在你不...
- Linux基础知识 | 文件与目录大全讲解
-
1.linux文件权限与目录配置1.文件属性Linux一般将文件可存取的身份分为三个类别,分别是owner/group/others,且三种身份各read/write/execute等权限文...
- 文件保护不妥协:2025 年 10 款顶级加密工具推荐
-
数据安全无小事,2025年这10款加密工具凭借独特功能脱颖而出,从个人到企业场景全覆盖,第一款为Ping32,其余为国外英文软件。1.Ping32企业级加密核心工具,支持200+文件格...
- 省心省力 一个软件搞定系统维护_省心安装在哪里能找到
-
◆系统类似于我们居住的房间,需要经常打理才能保持清洁、高效。虽然它本身也自带一些清理和优化的工具,但借助于好用的第三方工具来执行这方面的任务,会更让人省心省力。下面笔者就为大家介绍一款集多项功能于一身...
- JAVA程序员常用的几个工具类_java程序员一般用什么软件写程序
-
好的工具做起事来常常事半功倍,下面介绍几个开发中常用到的工具类,收藏一下,也许后面真的会用到。字符串处理:org.apache.commons.lang.StringUtilsisBlank(Char...
- 手工解决Windows10的若干难题_windows10系统卡顿怎么解决
-
【电脑报在线】很多朋友已经开始使用Win10,估计还只是测试版本的原因,使用过程中难免会出现一些问题,这里介绍解决一些解决难题的技巧。技巧1:让ProjectSpartan“重归正途”从10074...
- System32文件夹千万不能删除,看完这篇你就知道为什么了
-
C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发...
- Windows.old 文件夹:系统备份的解析与安全删除指南
-
Windows.old是Windows系统升级(如Win10升Win11)或重装时,系统自动在C盘创建的备份文件夹,其核心作用是保留旧系统的文件、程序与配置,为“回退旧系统”提供保...
- 遇到疑难杂症?Windows 10回收站问题巧解决
-
回收站是Windows10的一个重要组件。然而,我们在使用过程中,可能会遇到一些问题。例如,不论回收站里有没有文件,都显示同一个图标,让人无法判别回收站的空和满的真实情况;没有了像Windows7...
- 卸载软件怎么彻底删掉?简单几个步骤彻底卸载,电脑小白看过来
-
日常工作学习生活中,我们需要在安装一些软件程序,但随着软件的更新迭代速度,很多时候我们需要重新下载安装新的程序,这时就需要将旧的一些软件程序进行卸载。但是卸载软件虽然很简单,但是很多小伙伴们表示卸载不...
- 用不上就删!如何完全卸载OneDrive?
-
作为Windows10自带的云盘,OneDrive为资料的自动备份和同步提供了方便。然而,从隐私或其他方面考虑,有些人不愿意使用OneDrive。但Windows10本身不提供直接卸载OneDri...
- 【Linux知识】Linux下快速删除大量文件/文件夹方法
-
在Linux下,如果需要快速删除大量文件或文件夹,可以使用如下方法:使用rm命令删除文件:可以使用rm命令删除文件,例如:rm-rf/path/to/directory/*这个命令会递...
- 清理系统不用第三方工具_清理系统垃圾用什么软件
-
清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...
- 系统小技巧:软件卸载不了?这里办法多
-
在正常情况下,我们都是通过软件程序组中的卸载图标,或利用控制面板中的“程序和功能”模块来卸载软件的。但有时,我们也会发现利用卸载图标无法卸载软件或者卸载图标干脆丢失找不到了,甚至控制面板中卸载软件的功...
- 麒麟系统无法删除文件夹_麒麟系统删除文件权限不够
-
删除文件夹方法例:sudorm-rf文件夹名称。删除文件方法例:sudorm-r文件名包括扩展名。如果没有权限,给文件夹加一下权限再删。加最高权限chmod775文件名加可执行权限...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)