这篇文章发布于 2018年04月10日,星期二,22:37,归类于 JS相关。 阅读 47902 次, 今日 7 次 12 条评论
by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=7473
本文可全文转载,但需保留原作者和出处。
一、路还很远,慢慢走一点一点
JS的学习停滞了很久,当想要重新拾起的时候,发现已经拉了很多东西了。
然而,自己并不着急。朝花因故未采撷,夕拾依旧烂漫天。从小处开始,一点一点上下求索,漫漫长路就会全然走在脚下。
例如,从ES6一个名不见经传的Symbol()
方法说起。
//zxx: 本文部分内容参考自MDN上关于Symbol的文档。
二、关于symbol这个词
Symbol这个词在IT软件领域实际上是个常见角色,在传统前端技术领域,这个词出现频率有限,但是,随着现代web技术的发展,Symbol这个词开始在不同前端语言中出现。
symbol的中文意思是:符号;象征;标志;记号等。
我最早知道是在Adobe Illustrator软件中,作为一个矢量符号存在。在SVG中,就有专门的<symbol>
标签,用来指代SVG小图标。
在这里,Symbol又有了另外的角色,作为一个JavaScript的原生数据类型(primitive data type)存在。
说到JavaScript原生数据类型,我们通常想到的有这6种:undefined
、null
、boolean
、string
、number
、object
。而symbol
是ES6新增的一个原生数据类型。
而Symbol本身又是一个方法。
例如下面JS:
typeof Symbol();
可以看到Symbol()
作为一个方法执行了,同时typeof
其类型,也是'symbol'
,如下截图:
但Symbol不能作为构造函数使用,也就是下面这样是会嗝屁的!
new Symbol();
三、Symbol的作用是什么?
Symbol的作用非常的专一,换句话说其设计出来就只有一个目的——作为对象属性的唯一标识符,防止对象属性冲突发生。
举个例子,你看上了公司前来的前台妹纸,想了解关于她的更多信息,于是就询问Hr同事,扫地阿姨,于是得到类似这样信息:
let info1 = { name: '婷婷', age: 24, job: '公司前台', description: '平时喜欢做做瑜伽,人家有男朋友,你别指望了' } let info2 = { description: '这小姑娘挺好的,挺热情的,嘿嘿嘿……' }
显然,你需要对这两个数据进行汇总,结果,就会发现,描述都用了同一个对象属性description
,于是整合的时候,就容器冲突,覆盖,导致“人家有男朋友”这么重要的信息都没注意到。
但是,如果要是Symbol,则完全就不要担心这个问题了:
let info1 = { name: '婷婷', age: 24, job: '公司前台', [Symbol('description')]: '平时喜欢做做瑜伽,人家有男朋友,你别指望了' } let info2 = { [Symbol('description')]: '这小姑娘挺好的,挺热情的,嘿嘿嘿……' }
此时,我们对info1, info2对象进行复制,如下:
let target = {}; Object.assign(target, info1, info2);
此时target
对象如下截图所示:
妹纸所有的描述信息都被完完整整地保留了下来了。
因为Symbol()
返回值是唯一的,也就是:
Symbol('description') === Symbol('description'); // 返回值是false
四、Symbol()的语法
语法如下:
Symbol([description])
其中description
为可选参数,字符串,没什么特别的作用,就是debug调试的时候可以用来作为标记。
如何获取Symbol()对应属性值?
拿上面target
举例,如何获得对妹纸的description
描述信息呢?
我们可以使用Object.getOwnPropertySymbols(obj)
这个方法进行获取,可以返回obj
对象中的Symbol信息,例如:
Object.getOwnPropertySymbols(target);
妹纸的描述信息就出现了,如下截图:
Symbol在和对象使用的时候,往往离不开JS中的数组括号[]
,例如:
var smy = Symbol(); var info = { smy: 'x', [smy]: 'y' };
此时:
console.log(info.smy); // 输出'x' console.log(info['smy']); // 输出'x' console.log(info[smy]); // 输出'y'
五、Symbol其他一些知识
1. Symbol与运算、类型转换等
symbol
值虽然不是对象,但是根据自己测试,在Chrome和Firefox下都是可以添加属性的,例如:
var smy = Symbol(); smy.description = '描述';
更新于翌日
感谢yyhaxx的反馈,在macos chrome 65.0.3325.181和node v8.9.4中测试给symbol加属性结果是undefined
,与上面window PC测试结果有些细节差异。
但是在类型转换时候symbol
值会遇到不少局限:
- Symbol值可以显式转为字符串,也可以转为布尔值,但是不能转为数值。例如:
+sym
会报错,如下图:隐式地创建一个新的
string
类型的属性名也会报错,例如Symbol("foo") + "bar"
将抛出一个TypeError: - 使用宽松相等时,
Object(sym) == sym
返回值是true
。注意这里外面套的是Object()
;
2. Symbol与for…in迭代
Symbols在for...in
迭代中不可枚举,如果想要达到效果,借助Object.getOwnPropertySymbols(obj)
这个方法。
var obj = {};
obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";
for (var i in obj) {
console.log(i); // 输出 "c" 和 "d"
}
3. Symbol与JSON.stringify()
当使用JSON.strIngify()
时以symbol
值作为键的属性会被完全忽略,示意代码:
JSON.stringify({[Symbol("foo")]: "foo"}); // '{}'
4. Symbol包装器对象作为属性的键
围绕原始数据类型创建一个显式包装器对象从ECMAScript 6开始不再被支持,所以new Symbol()
会报错,然而,现有的原始包装器对象,如 new Boolean
、new String
以及new Number
因为遗留原因仍可被创建。
此时,如果我们想创建一个Symbol
包装器对象 (Symbol wrapper object),你可以使用Object()
函数:
var sym = Symbol("foo"); typeof sym; // "symbol" var symObj = Object(sym); typeof symObj; // "object"
当一个Symbol
包装器对象作为一个属性的键时,这个对象将被强制转换为它包装过的symbol
值:
var sym = Symbol("foo"); var obj = {[sym]: 1}; obj[sym]; // 1 obj[Object(sym)]; // 还是1
六、结束语
实用角度讲,上面关于Symbol()的知识已经足够了,实际上文档中虽然还展示了很多其他API和方法,例如Symbol在全局有个注册表,它为字符串和Symbol提供了一对一的关系,这种对应关系甚至是跨service worker和iframe的,可以通过使用Symbol.for(key)
返回Symbol
。
不过文中并没有详细介绍,因为本文标题是“简单介绍”,哈哈,开个玩笑,实际上考虑的是投资收益比,如果我们追求的不是成为在很高技术造诣的牛人,当下这个阶段,其实可以不必花太多时间过于深究,面向业务面向项目,收益要更大些。
好,就这些,真·简单介绍。
ECMAScript 6相关知识我自己也处于婴儿学步阶段,如果有表述不准确的地方,欢迎大力指正!
感谢阅读!
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=5474
(本篇完)
- 未来必热:SVG Sprites技术介绍 (0.426)
- CSS vector-effect与SVG stroke描边缩放 (0.426)
- Proxy是代理,Reflect是干嘛用的? (0.319)
- js面向数据编程(DOP)一点分享 (0.255)
- 翻译:ECMAScript 5.1简介 (0.255)
- 基于HTML模板和JSON数据的JavaScript交互 (0.255)
- JS前端创建html或json文件并浏览器导出下载 (0.255)
- 聊聊JS DOM变化的监听检测与应用 (0.213)
- 深入 JS new Function 语法 (0.213)
- 实用的JS对象分组静态方法Object.groupBy() (0.213)
- JS字符串补全方法padStart()和padEnd()简介 (RANDOM - 0.106)
这个例子举得真好,哈哈哈哈
油猴子脚本
eval(‘document.getElementsByTagName(“‘+selectorSlide+'”)’)[0].style.display = “none”
对于数据结构清晰的业务场景,感觉基本是鸡肋。
旭哥,可以问下为什么最新的html5Validate没有开源吗。。。。 感觉目前为止最好用的验证插件了。。。
已在LuLu UI中开源,demo地址:https://l-ui.com/content/apis/validate.html
学习了,感谢分享
旭哥。按照您的例子,我怎么取婷婷表述合并后的信息呢?
最近一段时间,阅读旭哥的 css世界收获颇丰,内容通俗易懂,完全可以当作一篇散文小说看了,推荐再多出点书,必买!!!
打扰了,张老师。刚才那条评论请您忽略,
是我看错了,误把 definded 理解成了 undefined,浪费您时间,真的非常抱歉!
旭哥,我这边在macos chrome 65.0.3325.181和node v8.9.4中测试给symbol加属性结果加不上具体如下:
var smy1 = Symbol()
undefined
smy1.description = ‘描述’
“描述”
smy1.description
undefined
好的,感谢反馈,我更新下~
我在windows,Chrome,QQ浏览器之类测试加属性没问题,但是取属性都是undefined!
var smy = Symbol();
smy.description = ‘描述’;
“描述”
“描述”
smy.description
undefined