为什么要将符号带入JavaScript?
正如你可能知道他们正计划在ECMAScript 6中包含新的Symbol原始types(更不用说其他一些疯狂的东西了)。 我一直认为Ruby中的:symbol
概念是不必要的, 我们可以轻松地使用纯string,就像我们在JavaScript中所做的一样。 现在他们决定用JS来使JS变得复杂。
我不明白这个动机。 有人可以向我解释我们是否真的需要JavaScript中的符号?
更新 :最近来自Mozilla的一篇精彩文章出现了。 如果你好奇,请阅读。
启用私有属性,如kangax在他的回答中所描述的,确实是将符号引入JavaScript的原始动机。
然而不幸的是,他们最终被严重降级,毕竟不是私有的,因为你可以通过反思find它们。 具体来说,通过Object.getOwnPropertySymbols
方法和代理。
他们现在被称为独特的符号,他们唯一的用途是避免名称之间的冲突属性。 例如,EcmaScript本身现在可以通过一些可以放在对象上的方法来引入扩展钩子(例如定义它们的迭代协议),而不会冒用户名冲突的风险。
这是否足够强大的动机,以添加符号的语言是值得商榷的。
符号不保证真实的隐私,但可以用来分隔对象的公共和内部属性。 举个例子,我们可以使用Symbol
来获得私有属性。
我们举一个例子,一个对象的属性不是私有的。
var Pet = (function() { function Pet(type) { this.type = type; } Pet.prototype.getType = function() { return this.type; } return Pet; }()); var a = new Pet('dog'); console.log(a.getType());//Output: dog a.type = null; //Modified outside console.log(a.getType());//Output: null
以上, Pet
类属性type
不是私有的。 为了保密,我们必须创build一个闭包。 下面的例子说明了我们如何使用闭包来实现私有type
。
var Pet = (function() { function Pet(type) { this.getType = function(){ return type; }; } return Pet; }()); var b = new Pet('dog'); console.log(b.getType());//dog b.type = null; //Stays private console.log(b.getType());//dog
上述方法的缺点:我们为每个创build的Pet
实例引入一个额外的闭包,这会损害性能。
现在我们介绍一下Symbol
。 这可以帮助我们在不使用额外的不必要的closures的情况下将财产私有化 下面的代码示例:
var Pet = (function() { var typeSymbol = Symbol('type'); function Pet(type) { this[typeSymbol] = type; } Pet.prototype.getType = function(){ return this[typeSymbol]; } return Pet; }()); var a = new Pet('dog'); console.log(a.getType());//Output: dog a.type = null; //Stays private console.log(a.getType());//Output: dog
这是我如何看待它。 通过Object.keys()和JSON.stringify()等一些stream行的方法,通过阻止对象的键/属性被暴露,符号提供了“额外的隐私级别”。
var age = Symbol(); // declared in another module perhaps? class Person { constructor(n,a){ this.name = n; this[age] = a; } introduce(){ console.log(`My name is ${this.name}. I am ${this[age]-10}.`); } } var j = new Person('Jane',45); j.introduce(); // My name is Jane. I am 35. console.log(JSON.stringify(j)); // {"name":"Jane"} console.log(Object.keys(j)); // ["name"] console.log(j[age]); // 45 (well…only if you know the age in the first place…)
虽然给定一个对象本身,这些属性仍然可以通过reflection,代理,Object.getOwnPropertySymbols()等暴露出来,但没有自然的方法通过几个直接的方法来访问它们,有时从OOP的angular度来看是足够的。
Symbols
是一种new
special
types的对象,可用作对象中的unique
属性名称。 使用symbols
而不是strings
允许不同的modules
创build不相互冲突的属性。 Symbols
也可以是private
,以便任何没有直接访问symbol
人都无法访问它们的属性。
Symbols
是一个new
原始 。 就像Number
, String
和Boolean
原语一样, Symbols
也有一个Symbol
函数可以用来创build它们。 与其他基元不同, Symbols
不具有字面语法(例如,string是如何具有的) – 创build它们的唯一方法是使用Symbol
构造函数,方法如下:
let symbol=Symbol();
实际上, Symbols
只是将属性附加到对象上的一种slightly
不同的方式 – 您可以很容易地提供well-known
符号作为标准方法,就像Object.prototype.hasOwnProperty
,它出现在inheritance自Object
所有东西中。
这是符号原始types的一些好处。
符号具有内置的可debugging性
Symbols
可以给出一个description
,这实际上只是用于debugging
,使他们logging到控制台时, life
变得更加容易。
符号可以用作对象键
这是Symbols
变得真正有趣的地方。 它们与Objects
heavily
交织在一起。 Symbols
可以指定为Objects
keys
(类似于string键),这意味着您可以将无限数量的唯一符号分配给对象,并保证这些符号永远不会与string键或其他唯一Symbols
冲突。
符号可以作为一个unique
价值。
假设您有一个logging
库,其中includes
多个日志levels
例如logger.levels.DEBUG
, logger.levels.INFO
, logger.levels.WARN
等等。 在ES5
代码中,你想使这些Strings
(如logger.levels.DEBUG === 'debug'
)或numbers
( logger.levels.DEBUG === 10
)。 这两个都不理想,因为这些值不是唯一的值,但Symbols
是! 所以logger.levels simply
变成:
log.levels = { DEBUG: Symbol('debug'), INFO: Symbol('info'), WARN: Symbol('warn'), }; log(log.levels.DEBUG, 'debug message'); log(log.levels.INFO, 'info message');
阅读更多在这个伟大的文章。