由於ES5的對象屬性名都是字符串,這容易形成屬性名的衝突。好比,你使用了他人提供的對象,但又想爲這個對象添加新的方法,新方法的名字就有可能與現有的方法產生衝突,全部就有了Symbol,它會保證每一個屬性名是獨一無二的,能夠從根本上防止屬性名的衝突。前端
ES6引入了一種新的原始數據類型 Symbol,表示獨一無二的值,它是Javascript語言的第七種數據類型。segmentfault
Symbol值經過 Symbol函數生成,對象的屬性名如今能夠有兩種類型,一種是原有的字符串,另外一種就是新增的Symbol類型。 Symbol類型是獨一無二的不會和其餘屬性名產生衝突數組
let s = Symbol()
typeof s
// 'Symbol'
複製代碼
注意: Symbol 函數前不能用 new命令,不然會報錯。由於生成的Symbol是一個原始類型的值,不是對象。**Symbol值不是對象,沒法爲其添加屬性。**它是一個相似字符串的數據類型函數
Symbol函數能夠接受一個參數,表示對Symbol實例的描述,方便在控制檯顯示,在轉爲字符串的時候方便區分,以下:post
let s1 = Symbol('foo');
let s2 = Symbol('far');
s1 // Symbol(foo)
s2 // Symbol(far)
s1.toString() // 'Symbol(foo)'
s2.toString() // 'Symbol(far)'
// 經過添加描述能夠區分究竟是哪一個Symbol值輸出了
複製代碼
若是 Symbol的參數是一個對象,那麼會調用該對象的toString()方法將其轉換成字符串,在生成Symbol值spa
const obj = {
toString() {
retrun 'abc'
}
}
const sym = Symbol(obj)
sym // Symbol(abc)
// 注意: Symbol函數的參數只是表示對當前Symbol值的描述,
所以相同參數的Symbol函數的返回值不一樣
let s1 = Symbol()
let s2 = Symbol()
s1 === s2 // false
let s1 = Symbol('cc')
let s2 = Symbol('cc')
s1 === s2 // false
複製代碼
注意: Symbol 值不能與其餘類型的值進行運算,會報錯。可是,Symbol值能夠顯式轉爲字符串。另外,Symbol值能夠轉換爲布爾值,可是不能轉爲數值。prototype
建立 Symbol的時候能夠添加一個描述。若是讀取這個描述,則須要將Symbol顯式轉爲字符串。可是這樣很不方便,因此在ES2019中提供 實例屬性 description 直接返回 Symbol的描述。3d
// 添加描述
const sym = Symbol('boo')
// 讀取描述
String(sym) // 'Symbol(boo)'
sym.toString() // 'Symbol(boo)'
// 新增方法
sym.description // 'boo'
複製代碼
由於 每個 Symbol值都是不相等的,這意味着 Symbol 值 能夠做爲標識符,用於對象的屬性名,就能保證不會出現同名的屬性,防止某一個鍵被不當心改寫 或 覆蓋。以下:code
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值必須發放在方括號之中。另外,Symbol值做爲屬性名時,該屬性仍是公開屬性,不是私有屬性。cdn
魔術字符串是指,在代碼之中出現屢次、與代碼造成強耦合的某一個具體的字符串或數值。
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔術字符串
area = .5 * options.width * options.height;
break;
/* ... more code ... */
}
return area;
}
getArea('Triangle', { width: 100, height: 100 }); // 魔術字符串
複製代碼
上述代碼中,字符串Triangle就是一個魔術字符串,它屢次出現。與代碼造成「強耦合」,不利於修改維護,經常使用的方法就是把它寫成一個變量。
const shapeType = {
triangle: 'Triangle'
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, { width: 100, height: 100 });
複製代碼
能夠發現 shapeType.triangle等於哪一個值並不重要,只要確保不會跟其餘的shapeType屬性衝突就行,這樣能夠用 Symbol 來代替。
const shapeType = {
triangle: Symbol()
};
複製代碼
Symbol做爲屬性名,該屬性不會出如今 for..in | for...of 循環中,也不會被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。可是它還有個私有屬性方法能夠獲取指定對象的全部Symbol屬性名。Object.getOwnPropertySymbols,它返回的是一個數組,成員是該對象全部用做屬性名的 Symbol值
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]
複製代碼
咱們還能夠 經過 新API Reflect.ownkeys方法 返回全部類型的鍵名,包括常規鍵名和 Symbol鍵名。
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
複製代碼
重點:因爲以Symbol值做爲名稱的屬性,不會被常規的方法遍歷到,咱們能夠利用這個特性爲對象定義一些非私有的,但又但願只用於內部的方法。
有時候咱們但願從新使用同一個 Symbol值,Symbol.for方法能夠作到這一點,它接受一個字符串做爲參數,而後搜索有沒有以該參數做爲名稱的Symbol值。若是又,就返回這個Symbol值,不然就新建並返回一個以該字符串爲名稱的Symbol值
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
複製代碼
區別: Symbol.for() 與 Symbol 這兩種寫法,都會生成新的Symbol,不一樣的是:
Symbol.keyFor方法返回一個已登記的 Symbol 類型值的key 就是和 Symbol.for()對應使用。
let s1 = Symbol.for('foo')
Symbol.keyFor(s1) // 'foo'
let s2 = Symbol('foo')
Symbol.keyFor(s2) // undefined
複製代碼
Singleton 模式指的是調用一個類,任什麼時候候返回的都是同一個實例。能夠經過將實例放到頂層對象global實現。
一個內部方法,當其餘對象使用 instanceof 運算符,判斷是否爲該對象的實例時會調用這個方法。
是一個布爾值,表示該對象用於 Array.prototype.caocat()時,是否能夠展開
指向一個構造函數,建立衍生對象時,會使用該屬性。它的做用在於,實例對象在運行過程當中,須要再次調用自身的構造函數時,會調用該屬性指定的構造函數。它的主要用途是,有些類庫是在基類的基礎上修改的。那麼子類使用繼承的方法時,但願返回的時基類的實例,而不是子類的實例。
指向一個函數,當執行 str.match(myObject)時,若是該屬性存在,則調用它,返回該方法的返回值。
對象的Symbol.replace屬性,指向一個方法。當對象被 String.prototype.replace方法調用的時候,會返回該方法的值。
對象的 Symbol.search屬性,指向一個方法,當該對象被 String.prototype.search 方法調用時,會返回該方法的值
對象調用Symbol.split屬性,指向一個方法,當該對象被 String.prototype.split 方法調用時,會返回該方法的值。
對象的 Symbol.iterator屬性,指向該對象默認的遍歷器方法
對象的Symbol.toPrimitive屬性,指向一個方法。該對象被轉爲原始類型的值時,會調用這個方法,返回該對象對應的原始類型值。Symbol.toPrimitive被調用時,會接受一個字符串參數,表示當前運算的模式,一共有三種模式。
對象的Symbol.toStringTag屬性,指向一個方法。在該對象上面調用Object.prototype.toString方法時,若是這個屬性存在,它的返回值會出如今toString方法返回的字符串之中,表示對象的類型。也就是說,這個屬性能夠用來定製[object Object]或[object Array]中object後面的那個字符串。
對象的 Symbol.unscopables 屬性,指向一個對象,該對象指定了使用 with 關鍵字時,哪些屬性會被 with 環境排除。
歡迎關注 公衆號【小夭同窗】
重學js系列
ES6入門系列
Git教程