將符號引入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 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章