恢復內容開始 1. Symbol 1.1 概述 保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol的原因 在es6之前,JavaScript數據類型分為 Number、Boolean、String、Null、Undefined、Object es ...
---恢復內容開始---
- Symbol
1.1 概述
保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol的原因
在es6之前,JavaScript數據類型分為
Number、Boolean、String、Null、Undefined、Object
es6中,新增了一個基本數據類型 Symbol
ES6 引入了一種新的原始數據類型Symbol,表示獨一無二的值。它是 JavaScript 語言的第七種數據類型,前六種是:undefined、null、布爾值(Boolean)、字元串(String)、數值(Number)、對象(Object)。
Symbol值是由Symbol函數調用產生的
對象的屬性名現在可以有兩種類型,一種是原來就有的字元串,另一種就是新增的 Symbol 類型。凡是屬性名屬於 Symbol 類型,就都是獨一無二的,可以保證不會與其他屬性名產生衝突。
let s = Symbol();
typeof s
// "symbol"
Symbol 函數不是構造函數,不能通過new 來構造一個Symbol實例,因為Symbol生成的是一個原始類型值,而不是對象。
Symbol函數可以接受一個字元串作為參數,表示對 Symbol 實例的描述,主要是為了在控制台顯示,或者轉為字元串時,比較容易區分。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
每一個Symbol都是獨一無二的
// 沒有參數的情況
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有參數的情況
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
另外,Symbol 值也可以轉為布爾值,Symbol 值不能與其他類型的值進行運算,會報錯。
1.2 作為屬性名的Symbol
由於每一個 Symbol 值都是不相等的,這意味著 Symbol 值可以作為標識符,用於對象的屬性名,就能保證不會出現同名的屬性。這對於一個對象由多個模塊構成的情況非常有用,能防止某一個鍵被不小心改寫或覆蓋。
let mySymbol = Symbol();
// 第一種寫法
let a = {};
a[mySymbol] = 'Hello!';
// 第二種寫法
let a = {
[mySymbol]: 'Hello!'
};
// 第三種寫法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上寫法都得到同樣結果
a[mySymbol] // "Hello!"
Symbol 值作為對象屬性名時,不能用點運算符,使用 Symbol 值定義屬性時,Symbol 值必須放在方括弧之中。
1.3 應用實例
屬性私有化 - 數據保護
場景:我們想創建一個構造函數Person,我們希望Person的性別在被創建後,就保存到死,無法改變。
這個時候我們就可以使用我們的Symbol作為Person屬性名:
var Person = (function() {
let _gender = Symbol('gender');
function P(name, gender) {
this.name = name;
this[_gender] = gender;
}
return P;
})();
var p1 = new Person('阿孔', '男');
console.log(p1);
上述代碼很簡單,我們使用Symbol函數創建一個Symbol值作為我們構造函數Person的一個屬性,性別。
可以看到,我們的Symbol性別屬性被添加到實例當中
此時如果我們想通過常規的方法來取我們的屬性值,
console.log(p1[Symbol('gender')])
我們預期的可能是能取到 “男”,但是取到的是undefined
這說明,我們此時的Symbol屬性外部只能看,不能讀,更不能改。大大的加強了屬性的私有化屬性。
但是我們可以在構造函數內部來獲取使用我們的值
在構造函數內部,我們可以在原型鏈上添加一個say方法
P.prototype.say = function() {
console.log(this[_gender]);
}
...
p1.say()
打開控制台,我們就可以看到 男 被列印了出來。
1.4 Symbol.for(),Symbol.keyFor()
Symbol.for()
Symbol.for()與Symbol()這兩種寫法,都會生成新的 Symbol。它們的區別是,前者會被登記在全局環境中供搜索,後者不會。Symbol.for()不會每次調用就返回一個新的 Symbol 類型的值,而是會先檢查給定的key是否已經存在,如果不存在才會新建一個值。比如,如果你調用Symbol.for("cat")30 次,每次都會返回同一個 Symbol 值,但是調用Symbol("cat")30 次,會返回 30 個不同的 Symbol 值。
有時,我們希望重新使用同一個 Symbol 值,Symbol.for方法可以做到這一點。它接受一個字元串作為參數,然後搜索有沒有以該參數作為名稱的 Symbol 值。如果有,就返回這個 Symbol 值,否則就新建並返回一個以該字元串為名稱的 Symbol 值。
Symbol.keyFor()
Symbol.keyFor方法返回一個已登記的 Symbol 類型值的key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
上面代碼中,變數s2屬於未登記的 Symbol 值,所以返回undefined。
1.5 內置的 Symbol 值
除了定義自己使用的 Symbol 值以外,ES6 還提供了 11 個內置的 Symbol 值,指向語言內部使用的方法。
Symbol目前最常用的地方就是作為對象的私有屬性去,更多更高級的內容可以訪問 http://es6.ruanyifeng.com/#docs/symbol
---恢復內容結束---