JavaScript Symbol對象
- 2020 年 7 月 29 日
- 筆記
- javascript
Symbol
Symbol
對象是es6
中新引進的一種數據類型,它的作用非常簡單,就是用於防止屬性名衝突而產生。
Symbol
的最大特點就是值是具有唯一性,這代表使用Symbol
類型的值能做獨一無二的一些事情。
此外,Symbol
沒有構造函數,這使得我們不能new
它,直接使用即可。
聲明Symbol
使用Symbol()
聲明一個獨一無二的值。
<script> "use strict"; let Sym1 = Symbol(); // 獨一無二的值 let Sym2 = Symbol(); console.log(typeof Sym1); // symbol console.log(Sym1 == Sym2); // false </script>
描述資訊
為Symbol
的值在聲明時添加一段描述資訊。
使用description
屬性可查看描述資訊。
注意:即使兩個
Symbol
的描述資訊是一樣的也不會有什麼問題,因為它僅僅是描述資訊而已。
<script> "use strict"; let Sym1 = Symbol("這是Sym1的描述資訊"); // 獨一無二的值 let Sym2 = Symbol("這是Sym2的描述資訊"); console.log(Sym1.description); // 這是Sym1的描述資訊 console.log(Sym2.description); // 這是Sym2的描述資訊 </script>
Symbol.for
使用Symbol()
來創建值不會進行記錄,所以無論值看起來是否一樣都不會引用同一份記憶體地址。
而使用Symbol.for()
來創建值則會進行記錄,下次再創建相同的值時會直接引用記錄的記憶體地址。
<script> "use strict"; let Sym1 = Symbol("測試"); // 獨一無二的值 let Sym2 = Symbol("測試"); console.log(Sym1 == Sym2); // false </script>
<script> "use strict"; let Sym1 = Symbol.for("測試"); // 將這個值的記憶體地址記錄,下次再創建時直接引用記憶體地址 let Sym2 = Symbol.for("測試"); console.log(Sym1 == Sym2); // true </script>
Symbol.keyFor
用於返回由Symbol.for()
創建的值的描述資訊。
如果值沒有描述資訊則返回undefined
。
當然,我們也可以使用description
屬性來獲取描述資訊,二者皆可。
<script> "use strict"; let Sym1 = Symbol.for("測試"); // 將這個值的記憶體地址記錄,下次再創建時直接引用記憶體地址 let Sym2 = Symbol.for(); console.log(Symbol.keyFor(Sym1)); // 測試 console.log(Symbol.keyFor(Sym2)); // undefined console.log(Sym1.description); // 測試 console.log(Sym2.description); // undefined </script>
實際應用
對象屬性
Js
中的對象(鍵)如果直接聲明就會變成String
類型,這在某些程度上可能會引起對象屬性衝突問題。
對象的鍵最好是唯一的,Symbol
類型的值無疑是最好的選擇。
當我們給想對象的鍵設置為Symbol
類型的值的時候需要注意2點問題。
Symbol
聲明和訪問使用[]
(變數)形式操作不能使用
.
語法因為.
語法是操作字元串屬性的
<script> "use strict"; let username = Symbol(); // 將這個值的記憶體地址記錄,下次再創建時直接引用記憶體地址 let age = Symbol(); let dic = { // 聲明時加上 [] 否則會變成String類型 --> "username" [username]:"雲崖", [age]:18, }; // 不能使用 . 語法獲取值(屬性) console.log(dic[username]); // 雲崖 console.log(dic[age]); // 18 </script>
對象遍歷
Symbol
類型值不能被 for/in
、for/of
遍歷操作找到。
以下示例可以看出,找不到兩個Symbol
類型的鍵。
<script> "use strict"; let username = Symbol(); // 將這個值的記憶體地址記錄,下次再創建時直接引用記憶體地址 let age = Symbol(); let dic = { // 聲明時加上 [] 否則會變成String類型 --> "username" [username]: "雲崖", [age]: 18, "gender": "男", }; for (let i in dic) { console.log(i); // gender } // for/of 只能遍歷一個迭代對象,不能直接遍歷對象。所以我們使用Object.keys(dic)將dic轉換為一個迭代對象。 for (let i of Object.keys(dic)) { console.log(i); // gender } </script>
可以使用 Object.getOwnPropertySymbols
獲取所有Symbol
屬性(鍵)。
注意,這是僅僅獲取Symbol
的屬性(鍵)。
<script> "use strict"; let username = Symbol(); // 將這個值的記憶體地址記錄,下次再創建時直接引用記憶體地址 let age = Symbol(); let dic = { // 聲明時加上 [] 否則會變成String類型 --> "username" [username]: "雲崖", [age]: 18, "gender": "男", }; for (let i in Object.getOwnPropertySymbols(dic)) { console.log(i); // 0 1 } // for/of 只能遍歷一個迭代對象,不能直接遍歷對象。所以我們使用Object.keys(dic)將dic轉換為一個迭代對象。 for (let i of Object.getOwnPropertySymbols(dic)) { console.log(i); // (2) Symbol() } </script>
也可以使用 Reflect.ownKeys(obj)
獲取所有屬性(鍵)包括Symbol
類型的屬性。
<script> "use strict"; let username = Symbol(); // 將這個值的記憶體地址記錄,下次再創建時直接引用記憶體地址 let age = Symbol(); let dic = { // 聲明時加上 [] 否則會變成String類型 --> "username" [username]: "雲崖", [age]: 18, "gender": "男", }; for (let i in Reflect.ownKeys(dic)) { console.log(i); // 0 1 2 } console.log("*".repeat(20)); // for/of 只能遍歷一個迭代對象,不能直接遍歷對象。所以我們使用Object.keys(dic)將dic轉換為一個迭代對象。 for (let i of Reflect.ownKeys(dic)) { console.log(i); // gender (2) Symbol() } </script>
私有屬性
我們可以使用Symbol
不能被for/in
以及for/of
訪問的特性,為類製作私有屬性以及提供訪問介面。
<script> "use strict"; const sex = Symbol("性別"); class User { constructor(name, age, gender) { this[sex] = gender; // 存入類對象中 this.name = name; this.age = age; } getMsg() { // 我們希望通過提供的API介面來讓用戶調出gender屬性 return `姓名:${this.name},年齡:${this.age},性別:${this[sex]}` } } let u1 = new User("雲崖", 18, "男"); console.log(u1.getMsg()); // 只能通過介面來拿到性別 姓名:雲崖,年齡:18,性別:男 // 如果循環不管是for/in還是for/of都是拿不到性別的 for (const i in u1) { console.log(i); // name // age } </script>