摘要:為此,存在一個全局注冊表。該調用會檢查全局注冊表,如果有一個描述為的,則返回該,否則將創建一個新,并通過給定的將其存儲在注冊表中。例如從全局注冊表中讀取如果該不存在,則創建它再次讀取相同的注冊表內的稱為全局。
Symbol 類型
根據規范,對象的屬性鍵只能是 String 類型或者 Symbol 類型。不是 Number,也不是 Boolean,只有 String 或 Symbol 這兩種類型。
到目前為止,我們只見過 String。現在我們來看看 Symbol 能給我們帶來什么好處。
Symbol"Symbol" 值表示唯一的標識符。
可以使用 Symbol() 來創建這種類型的值:
// id 是 symbol 的一個實例化對象 let id = Symbol();
我們可以給 Symbol 一個描述(也稱為 Symbol 名),這對于調試非常有用:
// id 是描述為 "id" 的 Symbol let id = Symbol("id");
Symbol 保證是唯一的。即使我們創建了許多具有相同描述的 Symbol,它們的值也是不同。描述只是一個不影響任何東西的標簽。
例如,這里有兩個描述相同的 Symbol —— 它們不相等:
let id1 = Symbol("id"); let id2 = Symbol("id"); *!* alert(id1 == id2); // false */!*
如果您熟悉 Ruby 或者其他有 "Symbol" 的語言 —— 別被誤導。JavaScript 的 Symbol 與眾不同。
JavaScript 中的大多數值都支持 string 的隱式轉換。例如,我們可以 `alert` 任何值,這會起作用。Symbol 是特別的,它無法自動轉換。 例如,這個 `alert` 將會顯示錯誤:
let id = Symbol("id");
!
alert(id); // 類型錯誤:無法將 Symbol 值轉換為 String。
/!
如果我們真的想顯示一個 Symbol,我們需要在它上面調用 `.toString()`,如下所示:
let id = Symbol("id");
!
alert(id.toString()); // Symbol(id),現在它起作用了
/!
這是一種防止混亂的“語言保護”,因為 String 和 Symbol 有本質上的不同,而且不應該偶爾將它們相互轉化。“隱藏”屬性
Symbol 允許我們創建對象的“隱藏”屬性,代碼的任何其他部分都不能偶爾訪問或重寫這些屬性。
例如,如果我們想存儲 object user 的“標識符”,我們可以使用 Symbol 作為它的鍵:
let user = { name: "John" }; let id = Symbol("id"); user[id] = "ID Value"; alert( user[id] ); // 我們可以使用 Symbol 作為鍵來訪問數據。
在 string "id" 上使用 Symbol("id") 有什么好處?
我們用更深入一點的示例來說明這一點。
假設另一個腳本希望 user 中有它自己的 "id" 屬性可以操作。這可能是另一個 JavaScript 庫,所以這些腳本完全不知道對方是誰。
然后該腳本可以創建自己的 Symbol("id"),如下所示:
// ... let id = Symbol("id"); user[id] = "Their id value";
不會沖突,因為 Symbol 總是不同的,即使它們有相同的名稱。
現在請注意,如果我們使用 String "id" 而不是用 symbol,那么就會出現沖突:
let user = { name: "John" }; //我們的腳本使用 "id" 屬性。 user.id = "ID Value"; // ...如果之后另一個腳本為其目的使用 "id"... user.id = "Their id value" // 砰!無意中重寫了 id!他不是故意傷害同事的,而是這樣做了!字面量中的 Symbol
如果我們要在 object 字面量中使用 Symbol,則需要方括號。
就像這樣:
let id = Symbol("id"); let user = { name: "John", *!* [id]: 123 // 不僅僅是 "id:123" */!* };
這是因為我們需要變量 id 的值作為鍵,而不是 String "id"。
Symbol 在 for..in 中被跳過Symbolic 屬性不參與 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) */!* // 被 Symbol 任務直接訪問 alert( "Direct: " + user[id] );
這是一般“隱藏”概念的一部分。如果另一個腳本或庫在我們的對象上循環,它不會訪問一個 Symbol 類型的屬性。
相反,Object.assign 同時復制字符串和符號屬性:
let id = Symbol("id"); let user = { [id]: 123 }; let clone = Object.assign({}, user); alert( clone[id] ); // 123
這里并不矛盾,就是這樣設計的。我們的想法是當我們克隆一個 object 或合并 object 時,通常希望所有屬性被復制(包括像 id 這樣的 Symbol)。
我們只能在對象中使用 string 或 symbol 作為鍵,其它類型轉換為 String。 例如,在作為屬性鍵使用時,數字 `0`變成了字符串 `"0"`:
let obj = {
0: "test" // same as "0": "test"
};
//兩個 alert 都訪問相同的屬性(Number 0 被轉換為 String "0")
alert( obj["0"] ); // test
alert( obj[0] ); // test (相同屬性)
正如我們所看到的,通常所有的 Symbol 都是不同的,即使它們有相同的名字。但有時我們想要同一個名字的 Symbol 是相同的實體。
比如,我們希望在應用程序的不同部分訪問相同的 Symbol "id" 屬性。
為此,存在一個全局 symbol 注冊表。我們可以在其中創建 Symbol 并在稍后訪問它們,它可以確保每次訪問相同名稱都會返回相同的 Symbol。
為了在注冊表中創建或讀取 Symbol,請使用 Symbol.for(key)。
該調用會檢查全局注冊表,如果有一個描述為 key 的 Symbol,則返回該 Symbol,否則將創建一個新 Symbol(Symbol(key)),并通過給定的 key 將其存儲在注冊表中。
例如:
// 從全局注冊表中讀取 let id = Symbol.for("id"); // 如果該 Symbol 不存在,則創建它 // 再次讀取 let idAgain = Symbol.for("id"); // 相同的 Symbol alert( id === idAgain ); // true
注冊表內的 Symbol 稱為全局 Symbol。如果我們想要一個應用程序范圍內的 Symbol,可以在代碼中隨處訪問 —— 這就是它們的用途。
在一些編程語言中,例如 Ruby,每個名稱都有一個 symbol。 在 JavaScript 中,我們應該用全局 symbol。Symbol.keyFor
對于全局 symbol,Symbol.for(key) 不僅按名稱返回一個 symbol,而且還有一個反向調用:Symbol.keyFor(sym),反過來:通過全局 symbol 返回一個名稱。
例如:
let sym = Symbol.for("name"); let sym2 = Symbol.for("id"); // 從 symbol 中獲取 name alert( Symbol.keyFor(sym) ); // name alert( Symbol.keyFor(sym2) ); // id
Symbol.keyFor 在內部使用全局 symbol 注冊表來查找 symbol 的鍵。所以它不適用于非全局 symbol。如果 symbol 不是全局的,它將無法找到它并返回 undefined。
例如:
alert( Symbol.keyFor(Symbol.for("name")) ); // name, 全局 Symbol alert( Symbol.keyFor(Symbol("name2")) ); // undefined, 參數不是一個全局 Symbol系統 Symbol
JavaScript 內部存在很多“系統” Symbol,我們可以使用它們來微調對象的各個方面。
它們列在熟悉的 Symbol 表的規范中:
Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.iterator
Symbol.toPrimitive
...等等。
例如,Symbol.toPrimitive 允許我們將對象描述為原始值轉換,我們很快就會看到它的使用。
當我們研究相應的語言特征時,其他 Symbol 也會變得熟悉起來。
總結Symbol 是唯一標識符的基本類型
Symbol 使用 Symbol() 創建的,調用帶有一個可選的描述。
Symbol 總是不同的值,即使它們有相同的名稱。如果我們希望同名 Symbol 相等,那么我們應該使用全局注冊表:Symbol.for(key) 返回(如果需要的話創建)一個以 key 作為名稱的全局 Symbol。Symbol.for 的多次調用完全返回相同的 Symbol。
Symbol 有兩個主要的使用場景:
“隱藏” 對象屬性。如果需要將屬性添加到 “屬于” 另一個腳本或庫的對象中,則可以創建 Symbol 并將其用作屬性鍵。Symbol 屬性不出現在 for..in中,因此不會無心列出。另外,它不會被直接訪問,因為另一個腳本沒有我們的符號,所以它不會不小心干預它的操作。
因此我們可以使用 Symbol 屬性“秘密地”將一些東西隱藏到我們需要的對象中,但其他人不會以對象屬性的形式看到它。
JavaScript 使用了許多系統 Symbol,這些 Symbol 可以作為 Symbol.* 訪問。我們可以使用它們來改變一些內置行為。例如,在本教程的后面部分,我們將使用 Symbol.iterator 來迭代,Symbol.toPrimitive 來設置對象原始值的轉換等等。
從技術上說,Symbol 不是 100% 隱藏的。有一個內置方法 Object.getOwnPropertySymbols(obj) 允許我們獲取所有的 Symbol。還有一個名為 Reflect.ownKeys(obj) 返回所有鍵,包括 Symbol。所以它們不是真正的隱藏。但是大多數庫、內置方法和語法結構都遵循一個共同的協議。而明確調用上述方法的人可能很清楚他在做什么。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/109372.html
摘要:迭代器在原有的數據結構類型上新增了兩種類型,我們在使用的時候還可以通過自由組合的形式使用這些結構類型達到自己想要的數據結構,這就需要一種統一的接口機制供我們調用處理不同的數據結構。 引言 萬丈高樓平地起,欲練此功,必先打好基本功: ) 在了解 ES6 新增的變量類型前,我們必須先知道 JavaScript 在ES6之前,有如下六種基本數據類型:Null、Undefined、Number...
摘要:但是,前來提到的個方法都不支持屬性,為了保持原有的功能,新增了一個方法來檢索類型的屬性接下來看一下式例以上,就是關于的基本使用方法。 ES6新增了一個基本數據類型:Symbol,至此ECMAScript的基本數據類型就有了6種:字符串,數字,布爾,null,undefined,Symbol。關于Symbol,我打算寫2篇文章來提取一下比較重要的知識點,這篇是第一篇,主要講Symbol的...
摘要:前端技術日新月異,不斷有新技術出現,我們就需要不斷地學習新知識,雖然已經提出很久了,但是最近我才有時間靜下心來好好學習一下里面提出的新規則。 前端技術日新月異,不斷有新技術出現,我們就需要不斷地學習新知識,雖然ES6已經提出很久了,但是最近我才有時間靜下心來好好學習一下里面提出的新規則。今天總結下ES6提出的這個新的原始數據類型--Symbol。 為啥需要Symbol 一個新規則的提出...
摘要:設置對象屬性只讀。提供了一個注冊機制,當你注冊之后,就能在全局共享注冊表里面的。的注冊表和對象表很像,都是結構,只不過這個是值。語法只有一個參數,返回的是從注冊表獲取全局共享的注意如果要防止命名重復問題,可以加上前綴。 還記得對象Object嗎? let obj = { a: 1 } 對象的格式: Object { key: value } 在ES5的時代,對象的key只能...
摘要:的碼點被稱為基本字符區域。關于的介紹,我準備用文檔阮一峰來做一些介紹,具體的可以參考文檔引入的原因的對象屬性名都是字符串,這容易造成屬性名的沖突。其他的一些屬性可以去看文檔阮一峰注意函數前不能使用命令,否則會報錯。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完...
閱讀 3492·2021-11-18 10:07
閱讀 1590·2021-11-04 16:08
閱讀 1515·2021-11-02 14:43
閱讀 1093·2021-10-09 09:59
閱讀 846·2021-09-08 10:43
閱讀 1084·2021-09-07 09:59
閱讀 968·2019-12-27 11:56
閱讀 1016·2019-08-30 15:56