首頁  >  文章  >  web前端  >  Javascript中關於Symbol類型的具體詳解

Javascript中關於Symbol類型的具體詳解

黄舟
黄舟原創
2017-08-08 14:06:002875瀏覽


Javascript中關於Symbol類型的具體詳解

根據規範,物件屬性鍵只能是string類型或symbol類型,不能是number、boolean,只有string和symbol兩種類型。
我們一般比較屬性string,現在來看看symbols類型帶給我們的優勢。

Symbols

“Symbol”值代表以給定名稱作為唯一識別。這種類型的值可以這樣創建:Symbol(name):

// id is a symbol with the name "id"
let id = Symbol("id");

Symbols確保唯一,即使我們使用相同的名稱,也會產生不同的值。舉例,這裡有兩個symbol使用相同的名稱,兩種不相等:

let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false

如果你熟悉Ruby或其他語言,也有相同類型的symbol,不要被誤導,Javascript的symbol是不同的。

隱藏屬性

symbol允許建立物件的隱藏屬性,這樣其他程式碼不會偶爾存取或覆寫。
舉例,如果我們想要儲存物件user的“identifier”,我們可以建立id的symbol:
   let user = { name: “John” };
   let id = Symbol(“id”);

user[id] = "ID Value";
alert( user[id] ); // we can access the data using the symbol as the key

現在讓我們想像假設另外的腳本想為user物件新增自己的「id」屬性,為其自有的目的。可能是另外其他的Javascript庫,所以完全互相不清楚彼此。
沒有問題,能夠創造自己的Symbol("id")

程式碼如下:

// ...
let id = Symbol("id");

user[id] = "Their id value";

這是沒有衝突的,因為symbol總是不同的,即使有相同的名稱。注意如果我們使用字串“id”代替symbol實現相同目的,那麼會有衝突:

let user = { name: "John" };

// our script uses "id" property
user.id = "ID Value";

// ...if later another script the uses "id" for its purposes...

user.id = "Their id value"
// boom! overwritten! it did not mean to harm the colleague, but did it!

直接量使用symbol

#如果我們在一個直接量物件中使用symbol,我們需要使用方括號:

let id = Symbol("id");

let user = {
  name: "John",
  [id]: 123 // not just "id: 123"
};

因為我們需要名稱為「id」的symbol變數值,不是字串「id」。

Symbol 被for…in 忽略

symbol屬性不參與for..in循環,舉例:

let id = Symbol("id");
let user = {
  name: "John",
  age: 30,
  [id]: 123
};

for(let key in user) alert(key); // name, age (no symbols)

// the direct access by the symbol works
alert( "Direct: " + user[id] );

這時一般隱藏概念的一部分,如果其他腳本或函式庫,也不期望訪問symbol屬性。
相反,Object.assign同時拷貝字元屬性和symbol屬性。

let id = Symbol("id");
let user = {
  [id]: 123
};

let clone = Object.assign({}, user);

alert( clone[id] ); // 123

這兩者沒有矛盾,規範就是這麼設計的,其思想是當我們克隆對像或合併對象,通常希望symbol屬性也被拷貝。

其他類型的屬性鍵被強制轉換成字串:

物件中的鍵只能使用字串或symbol,其他類型強制被轉換成字串。

let obj = {
  0: "test" // same as "0": "test"
}

// both alerts access the same property (the number 0 is converted to string "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (same property)

全域symbol

通常,所有symbol是不同的,但有時我們想相同名詞的symbol是相同的。舉例,我們應用不同部分想訪問名詞為”id“的symbol,當然需要是相同的。
可以透過全域symbol註冊實現,我們能先創建,然後訪問他們,並且保證透過相同名詞重複訪問獲得相同的symbol。

在註冊中建立或讀取,使用語法為:symbol.for(name),舉例:

// read from the global registry
let name = Symbol.for("name"); // if the symbol did not exist, it is created

// read it again
let nameAgain = Symbol.for("name");

// the same symbol
alert( name === nameAgain ); // true

在註冊中symbol稱為全域symbol,如果我們有應用範圍的symbol,代碼都可以訪問,可以使用全域symbol。

其他程式語言,想Ruby,每個名詞有單一symbol,在javascript中,我們知道,正是全局symbol。

Symbol.keyFor

對全域symbol,不僅有Symbol.for(name),根據名稱傳回symbol,也有相反的呼叫:Symbol.keyFor (name),功能相反:根據全域symbol傳回名稱。
範例:

let sym = Symbol.for("name");
let sym2 = Symbol.for("id");

// get name from symbol
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id

Symbol.keyfor內部實現,使用全域symbol註冊,根據symbol尋找symbol名稱。
所以對非全局的symbol不其作用,如果不是全域symbol,則找不到,回傳undefined。

範例:

alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol

alert( Symbol.keyFor(Symbol("name2")) ); // undefined, non-global symbol

非全域symbol,名稱僅用於偵錯目的。

系統symbol

在Javascript內部存在著許多系統symbol,我們可以使用他們調整物件的各個面向。
這裡列出一些常用的symbol:

  • Symbol.hasInstance

  • Symbol.isConcatSpreadable

  • #Symbol.iterator

  • Symbol.toPrimitive

##範例:

Symbol.toPrimitive用於對象轉基本型別時描述對象,如果你繼續深入學習Javascript,其他的你也會逐步熟悉。

總結

  • symbol是基本型,實作唯一標識

  • 透過呼叫

    symbol(name)創建symbol

  • 我們創建一個字段,僅為知道對應symbol的人能訪問,使用symbol很有用

  • ##symbol不會出現在for..in結果中
  • 使用symbol(name)創建的symbol,總是不同,即使name相同。如果希望相同名稱的symbol相等,則使用全域註冊
  • symbol.for(name)傳回給定名稱的全域symbol,多次呼叫傳回相同symbol
  • #Javascript有系統symbol,透過Symbol.*存取。我們能使用他們去修改一些內建行為。

技術上,symbol並不是100%隱藏,有內建方法Object.getOwnPropertySymbols(obj)可以得到所有的symbol。
也有一個方法Reflect.ownKeys(obj)傳回物件所有的鍵,包括symbol。

所以並不是真正隱藏。但大多數庫內建方法和語法結構遵循通用約定他們是隱藏的,如果某人顯示調用上述方法,可能完全理解他正在做什麼。

以上是Javascript中關於Symbol類型的具體詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn