将符号引入ES6的动机是什么?

本文翻译自:What is the motivation for bringing Symbols to ES6?

UPDATE : Recently a brilliant article from Mozilla came up. 更新 :最近有来自Mozilla精彩文章出现。 Read it if you're curious. 好奇的话请阅读。

As you may know they are planning to include new Symbol primitive type in ECMAScript 6 (not to mention some other crazy stuff). 如您所知,他们计划在ECMAScript 6中包括新的Symbol原语类型(更不用说其他疯狂的东西了)。 I always thought that the :symbol notion in Ruby is needless; 我一直认为Ruby中的:symbol概念是不必要的; we could easily use plain strings instead, like we do in JavaScript. 我们可以像使用JavaScript一样轻松地使用纯字符串。 And now they decide to complicate things in JS with that. 现在,他们决定将JS中的内容复杂化。

I don't understand the motivation. 我不明白动机。 Could someone explain to me whether we really need symbols in JavaScript? 有人可以向我解释我们是否真的需要JavaScript中的符号?


#1楼

参考:https://stackoom.com/question/1T9UM/将符号引入ES-的动机是什么


#2楼

The original motivation for introducing symbols to Javascript was to enable private properties. 将符号引入Javascript的最初动机是启用私有属性。

Unfortunately, they ended up being severely downgraded. 不幸的是,它们最终被严重降级。 They are no longer private, since you can find them via reflection, for example, using Object.getOwnPropertySymbols or proxies. 它们不再是私有的,因为您可以通过反射找到它们,例如,使用Object.getOwnPropertySymbols或代理。

They are now known as unique symbols and their only intended use is to avoid name clashes between properties. 它们现在被称为唯一符号,它们的唯一用途是避免属性之间的名称冲突。 For example, ECMAScript itself can now introduce extension hooks via certain methods that you can put on objects (eg to define their iteration protocol) without risking them to clash with user names. 例如,ECMAScript本身现在可以通过某些方法引入扩展挂钩,您可以将这些挂钩应用于对象(例如,定义其迭代协议),而不必冒与用户名冲突的风险。

Whether that is strong enough a motivation to add symbols to the language is debatable. 是否足够强大,是否有动机在语言中添加符号尚有争议。


#3楼

Symbols do not guarantee true privacy but can be used to separate public and internal properties of objects. 符号不能保证真正的私密性,但可以用于分隔对象的公共属性和内部属性。 Let's take an example where we can use Symbol for having private properties. 让我们举一个例子,我们可以使用Symbol来拥有私有属性。

Let's take an example where a property of an object is not private. 让我们举一个对象的属性不是私有的例子。

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

Above, the Pet class property type is not private. 上面的Pet类属性type不是私有的。 To make it private we have to create a closure. 要使其私有,我们必须创建一个闭包。 The below example illustrates how we can make type private using a closure. 以下示例说明了如何使用闭包将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

Disadvantage of above approach: We are introducing an extra closure for each Pet instance created, which can harm performance. 上述方法的缺点:我们为创建的每个Pet实例引入了一个额外的封闭,这可能会损害性能。

Now we introduce Symbol . 现在我们介绍Symbol This can help us make a property private without using extra unnecessary closures. 这可以帮助我们在不使用额外不必要的闭包的情况下将属性设为私有。 Code example below: 下面的代码示例:

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

#4楼

Here is how I see it. 这是我的看法。 Symbols provide 'an extra level of privacy', by preventing the keys/properties of an object from being exposed through some popular methods such as Object.keys() and JSON.stringify(). 通过防止对象的键/属性通过一些流行的方法(例如Object.keys()和JSON.stringify())公开,符号可提供“额外的隐私级别”。

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…)

Although given an object per se, such properties can still be exposed through reflection, proxy, Object.getOwnPropertySymbols() etc., there is no natural means to access them through a few direct methods, which may be sufficient sometimes from an OOP perspective. 尽管给定一个对象本身,但仍可以通过反射,代理,Object.getOwnPropertySymbols()等公开这些属性,但是没有自然的方法可以通过一些直接方法访问它们,从OOP角度看,有时这些方法就足够了。


#5楼

Symbols are a new, special kind of object that can be used as a unique property name in objects. Symbols是一种新的特殊对象,可以用作对象中的唯一属性名称。 Using Symbol instead of string 's allows different modules to create properties that don't conflict with one another. 使用Symbol而不是string允许不同的模块创建彼此不冲突的属性。 Symbols can also be made private, so that their properties can't be accessed by anyone who doesn't already have direct access to the Symbol . 也可以将Symbols设置为私有,以便尚无直接访问Symbol权限的任何人都不能访问它们的属性。

Symbols are a new primitive . Symbols是一个新的原语 Just like the number , string , and boolean primitives, Symbol have a function which can be used to create them. 就像numberstringboolean原语一样, Symbol具有可以用来创建它们的函数。 Unlike the other primitives, Symbols do not have a literal syntax (eg how string have '' ) - the only way to create them is with the Symbol constructor in the following way: 与其他原语不同, Symbols没有文字语法(例如string如何具有'' )-创建它们的唯一方法是使用Symbol构造函数,其方式如下:

let symbol = Symbol();

In reality, Symbol 's are just a slightly different way to attach properties to an object - you could easily provide the well-known Symbols as standard methods, just like Object.prototype.hasOwnProperty which appears in everything that inherits from Object . 实际上, Symbol只是将属性附加到对象的一种略有不同的方式-您可以轻松地提供众所周知的Symbols作为标准方法,就像Object.prototype.hasOwnProperty一样,它出现在从Object继承的所有内容中。

Here are some of the benefits of the Symbol primitive type. 以下是Symbol原语类型的一些好处。

Symbols have debuggability built in Symbols具有内置的可调试性

Symbols can be given a description, which is really just used for debugging to make life a little easier when logging them to a console. 可以给Symbols一个描述,它实际上只是用于调试,以便在将它们登录到控制台时使生活更轻松。

Symbols can be used as Object keys Symbols可以用作Object

This is where Symbol 's get really interesting. 这是Symbol变得非常有趣的地方。 They are heavily intertwined with objects. 它们与对象紧密地交织在一起。 Symbol can be assigned as keys to objects, meaning you can assign an unlimited number of unique Symbol 's to an object and be guaranteed that these will never conflict with string keys, or other unique Symbols . 可以将Symbol分配为对象的键,这意味着您可以为对象分配无限数量的唯一Symbol ,并确保它们永远不会与string键或其他唯一Symbols冲突。

Symbols can be used as a unique value. 可以将Symbols用作唯一值。

Let's assume you have a logging library, which includes multiple log levels such as logger.levels.DEBUG , logger.levels.INFO , logger.levels.WARN and so on. 让我们假设你有一个日志库,其中包括多个日志级别如logger.levels.DEBUGlogger.levels.INFOlogger.levels.WARN等。 In ES5 code you'd like make these string s (so logger.levels.DEBUG === 'debug' ), or number s ( logger.levels.DEBUG === 10 ). 在ES5代码中,您想将这些string s(所以logger.levels.DEBUG === 'debug' )或number s( logger.levels.DEBUG === 10 )。 Both of these aren't ideal as those values aren't unique values, but Symbol s are! 这两个都不是理想的,因为这些值不是唯一值,但是Symbol是! So logger.levels simply becomes: 所以logger.levels变成:

log.levels = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn'),
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');

Read more in this great article . 在这篇伟大的文章中阅读更多内容


#6楼

This post is about the Symbol() , supplied with actual examples I could find/make and facts & definitions I could find. 这篇文章是关于Symbol() ,提供了我可以找到/制作的实际示例以及我可以找到的事实和定义。

TLDR; TLDR;

The Symbol() is the data type, introduced with the release of ECMAScript 6 (ES6). Symbol()是随ECMAScript 6(ES6)发行版一起引入的数据类型。

There're two curious facts about the Symbol. 关于符号有两个奇怪的事实。

  • the first data type and only data type in JavaScript which has got no literal JavaScript中的第一个数据类型,也是唯一的没有文字的数据类型

  • any variable, defined with Symbol() , gets unique content, but it's not really private . 任何用Symbol()定义的变量都可以获取唯一的内容,但是它并不是真正的私有的

  • any data has its own Symbol, and for the same data the Symbols would be the same . 任何数据都有其自己的符号,对于相同的数据,符号将是相同的 More info in the following paragraph, otherwise it's not a TLRD; 下一段中的更多信息,否则它不是TLRD; :) :)

How do I initialise the symbol? 如何初始化符号?

1. To get a unique identifier with a debuggable value 1.获取具有可调试值的唯一标识符

You can do it either this way: 您可以通过以下方式之一进行操作:

var mySymbol1 = Symbol();

Or this way: 或者这样:

var mySymbol2 = Symbol("some text here");

The "some text here" string can't be extracted from the symbol, it's just a description for debugging purposes. 不能从符号中提取"some text here"字符串,这只是出于调试目的的描述。 It doesn't change the behaviour of symbol in any way. 它不会以任何方式改变符号的行为。 Although, you could console.log it (which is fair, since the value is for debugging, so as not to mistake that log with some other log entry): 虽然,您可以console.log它(这是公平的,因为该值用于调试,以免将该日志与其他日志条目相混淆):

console.log(mySymbol2);
// Symbol(some text here)

2. To obtain a symbol for some string data 2.获取一些字符串数据的符号

In this case the value of symbol is actually taken into account and this way two symbols may be non-unique. 在这种情况下, 实际上会考虑符号的值,这样两个符号可能是不唯一的。

var a1 = Symbol.for("test");
var a2 = Symbol.for("test");
console.log(a1 == a2); //true!

Let's call those symbols "second-type" symbols. 我们将这些符号称为“第二类型”符号。 They do not intersect with the "first-type" symbols (ie the ones defined with Symbol(data) ) in any way. 它们不以任何方式与“第一类型”符号(即使用Symbol(data)定义的Symbol(data)相交。

The next two paragraphs pertain only the the first-type symbol. 接下来的两段仅与第一种类型的符号有关。

How do I benefit from using Symbol instead of the older data types? 使用Symbol代替旧的数据类型有什么好处?

Let's first consider an object, a standard data type. 首先让我们考虑一个对象,一种标准的数据类型。 We could define some key-values pairs there and have an access to the values by specifying the key. 我们可以在那里定义一些键-值对,并可以通过指定键来访问这些值。

var persons = {"peter":"pan","jon":"doe"};
console.log(persons.peter);
// pan

What if we have two persons with the name Peter? 如果我们有两个叫Peter的人怎么办?

Doing this: 这样做:

var persons = {"peter":"first", "peter":"pan"};

wouldn't make much sense. 不会有多大意义。

So, appears to be a problem of two absolutely different persons having a same name. 因此,似乎是两个绝对不同的人具有相同名称的问题。 Let's then refer out new Symbol() . 然后让我们引用新的Symbol() It's like a person in real life - any person is unique , but their names can be equal. 就像现实生活中的一个人一样-任何人都是唯一的 ,但他们的名字可以相等。 Let's define two "persons". 让我们定义两个“人”。

 var a = Symbol("peter");
 var b = Symbol("peter");

Now we have got two different persons with the same name. 现在,我们有了两个同名的不同人。 Are our persons different indeed? 我们的人确实不同吗? They are; 他们是; you can check this: 您可以检查以下内容:

 console.log(a == b);
 // false

How do we benefit there? 我们在那里如何受益?

We can make two entries in your object for the different persons and they can't be mistaken in any way. 我们可以在您的对象中为不同的人输入两个条目,并且不能以任何方式将它们弄错。

 var firstPerson = Symbol("peter");
 var secondPerson = Symbol("peter");
 var persons = {[firstPerson]:"first", [secondPerson]:"pan"};

Note: 注意:
It's worth to notice, though, that stringifying the object with JSON.stringify will drop all the pairs initialised with a Symbol as a key. 但是,值得注意的是,使用JSON.stringify对对象进行字符串化将删除所有以Symbol为键进行初始化的对。
Executing Object.keys won't either return such Symbol()->value pairs. 执行Object.keys不会返回此类Symbol()->value对。

Using this initialisation, it's absolutely impossible to mistake the entries for the first and second persons. 使用此初始化,绝对不可能将输入的内容误认为第一人称和第二人称。 Calling console.log for them will correctly output their second names. 为他们调用console.log将正确输出他们的名字。

 console.log(persons[a]);
 // first
 console.log(persons[b]);
 // pan

When used in object, how it is different compared to defining non-enumerable property? 在对象中使用时,与定义不可枚举属性相比有何不同?

Indeed, there already existed a way to define a property to be hidden from Object.keys and enumeration. 实际上,已经存在一种定义要从Object.keys和枚举中隐藏的属性的方法。 Here it is: 这里是:

var anObject = {};
var fruit = "apple";    

Object.defineProperty( anObject, fruit, {
    enumerable: false,
    value: "green"
});

What difference does Symbol() bring there? Symbol()带来什么不同? The difference is that you can still get the property defined with Object.defineProperty in the usual way: 不同之处在于,您仍然可以以通常的方式获取用Object.defineProperty定义的属性:

console.log(anObject[fruit]); //green
console.log(anObject["apple"]); //green
console.log(anObject.apple); //green

And if defined with Symbol as in previous paragraph: 如果使用上一段中的Symbol进行定义:

fruit = Symbol("apple");

You will have an ability to receive its value only if knowing its variable, ie 只有知道变量的值,您才能接收它的值,即

console.log(anObject[fruit]); //green
console.log(anObject["apple"]); //undefined
console.log(anObject.apple); //undefined

Moreover, defining another property under the key "apple" will make the object drop the older one (and if hard-coded, it could throw an error). 此外,在键"apple"下定义另一个属性将使该对象删除较旧的属性(并且如果进行硬编码,则可能会引发错误)。 So, no more apples! 因此,没有更多的苹果了! That's a pity. 真可惜。 Referring the previous paragraph, the Symbols are unique and defining a key as Symbol() will make it unique. 参考上一段,符号是唯一的,将键定义为Symbol()将使其唯一。

Type conversion and checking 类型转换和检查

  • Unlike other data types, it's impossible to convert the Symbol() to any other data type. 与其他数据类型不同,不可能将Symbol()转换为任何其他数据类型。

  • It's possible to "make" a symbol based on primitive data type by calling Symbol(data) . 通过调用Symbol(data)基于原始数据类型“制作”符号。

  • In terms of checking the type, nothing changes. 在检查类型方面,没有任何变化。

     function isSymbol ( variable ) { return typeof someSymbol === "symbol"; } var a_Symbol = Symbol("hey!"); var totally_Not_A_Symbol = "hey"; console.log(isSymbol(a_Symbol)); //true console.log(isSymbol(totally_Not_A_Symbol)); //false 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值