ES6精華:Symbol

它是JS的第七種類型,屬於基本類型。
它表示一個獨一無二的值,行爲相似字符串。
它是直接經過Symbol函數生成的,能夠傳入字符做爲該值的描述。api

const symbol1 = Symbol('unique');
const symbol2 = Symbol('unique');
console.log(symbol1 === symbol2); // false

應用舉例

替代用於識別的字符串常量數組

--- 以前
const MY_ONE = 'unique-one';
if (MY_ONE === 'unique-one') { ... }
雖然定義了保存值的常量,但直接使用值或再定義相同值的變量也是沒有問題的。

--- 如今
const MY_ONE = Symbol('one');
if (MY_ONE === MY_ONE) { ... }
若是想使用該常量,必須直接使用該常量或其一個副本,由於 Symbol('one') 是絕對惟一的。

做爲間接實現私有屬性和方法的途徑函數

只有使用 private_a / private_b 變量所指向的值才能訪問到相應的屬性值。

const private_a = Symbol('private_a');
const private_b = Symbol('private_b');

function Class() {
  this[private_a] = 'private_a';
}

Class.prototype[private_b] = function() {
  console.log('private_b');
}

做爲自定義接口或不一樣數據集合統一接口的名稱this

示例:爲 Array 增長並集的計算方法,使用此方法能夠避免將來可能的命名衝突。

const CusArrayAPIMap = {
  union: Symbol('cus-array-api-union')
};

Array[CusArrayAPIMap.union] = function() {
  return [...new Set([...arguments].reduce((a, b) => a.concat(b), []))];
};

Array[CusArrayAPIMap.union]([1, 3], [2, 3]); // [1, 3, 2]

轉化規則

symbol值不可轉化成數字(做爲一個惟一值無對應的數值)。
symbol值能夠轉化成布爾值(無論怎樣,它是有值的,因此恆爲true)。
symbol值不可被隱式轉化成字符串,可是能夠顯示轉化(隱式即計算,拿一個惟一值計算沒意義,但直接打印成字符串查看是能夠的)。prototype

Symbol() + 2; // 報錯
Number(Symbol()); // 報錯

Boolean(Symbol()); // 恆爲 true
if (Symbol()) { ... } // 恆執行

Symbol() + '-'; // 報錯
String(Symbol()); // "Symbol()"
Symbol().toString(); // "Symbol()"

Symbol.for()

Symbol.for(key)Symbol()同樣,用來返回一個惟一值。
不過其傳入的key與生成的值會造成映射存儲在全局的symbol註冊表中。
便是說,Symbol.for(key)是先根據key在註冊表中尋找,有直接返回,沒有建立並返回。
也便是說,在相同的全局空間中(包括不一樣的iframeservice worker)傳入相同的key取出來的是同一值。code

Symbol('one') === Symbol('one'); // false
Symbol('one') === Symbol.for('one'); // false
Symbol.for('one') === Symbol.for('one'); // true
Symbol.for('one') === Symbol.for('two'); // false

相配套的還有方法Symbol.keyFor()
它會根據傳入的Symbol值,去註冊表中查找並返回對應的key對象

let o = Symbol.for('one');

Symbol.keyFor(o); // 'one'
Symbol.keyFor(Symbol('two')); // undefined
Symbol.keyFor(Symbol.for('two')); // 'two'

內置的 Symbol 值

ES6規定了11個內置接口的統一名稱。
能夠將這些接口部署到自定義對象或構造函數上,同步原生操做。繼承

Symbol.toStringTag
指向一個字符串,表示該對象的類型標籤。
通俗的說,就是使用Object.prototype.toString.call(target)獲取到的[object Name]中的Name接口

let obj = {
  [Symbol.toStringTag]: 'MyTag'
};
console.log( Object.prototype.toString.call(target) ); // '[object MyTag]'

Symbol.toPrimitive
指向一個方法,當該對象被轉化成NumberString型時會被調用。
該方法會接受一個字符串參數,表示當前場合須要轉化成什麼類型,一共有三種模式:numberstringdefault(轉化成二者都行)。ci

let obj = {
  [Symbol.toPrimitive](type) {
    switch(type) {
      case 'number':
        return 3;
        break;
      case 'string':
        return 's';
        break;
      case 'default':
        return 'd';
        break;
    }
  }
};

console.log( Number(obj) ); // 3
console.log( String(obj) ); // 's'
console.log( obj + 1 );  // 'd1'

Symbol.hasInstance
指向一個方法,是instanceof命令實際調用的方法。

[] instanceof Array; // true
實際是執行下面代碼。
Array[Symbol.hasInstance]([]); // true

可自行爲自定義對象添加此接口。
let OBJ = {
  [Symbol.hasInstance](arr) {
    return arr.length === 2 ? true : false;
  }
};
[1] instanceof OBJ; // false
[1, 2] instanceof OBJ; // true

Symbol.iterator
指向對象的默認遍歷器方法(關於遍歷器可看Iterator章節)。
數組默認的遍歷器方法爲:Array.prototype[Symbol.iterator]

Symbol.species
指向一個方法,該方法返回一個構造函數。當實例須要調用自身的構造函數時方法會被調用。
有些類庫是在基類的基礎上修改的,當子類使用繼承的方法時,做者但願返回基類的實例,而不是子類的實例。

class MyArray extends Array {
  static get [Symbol.species]() { return Array }
}

let a = new MyArray(1, 2, 3);
let b = a.map(x => x);
console.log(b instanceof Array); // true
console.log(b instanceof MyArray); // false

b 是 a 的衍生對象,或稱派生對象。
若是沒有 [Symbol.species] ,b 原型鏈中第一個對象應爲 MyArray 原型。
但如今第一個對象爲 Array 的原型,即 b 直接爲 Array 的實例。

Symbol.split, Symbol.match, Symbol.search, Symbol.replace
四者都是針對字符串與正則(對象)的關係,指向一個方法,具備相同行爲。

let reg = /m/g;
let str = 'Hi, I\'m programmer monkey';

str.replace(reg, 'M');
實際是執行下面的代碼。
reg[Symbol.replace](str, 'M');

Symbol.isConcatSpreadable
指向一個布爾值,表示該對象用於Array.prototype.concat()時是否能夠展開。
默認沒有該屬性,即爲undefined,等同於true。設置爲false則不展開。

let arr = [1, 2];
arr[Symbol.isConcatSpreadable] = false;
[3].concat(arr); // [3, [1, 2]]

Symbol.unscopables
指向一個對象,該對象指定了使用with關鍵字時,哪些屬性會被with環境排除。

let obj = {
  id: '123',
  name: 'limo',
  [Symbol.unscopables]: {
    id: true
  }
};

let id = 'id';
let name = 'name';

with (obj) {
  console.log(id); // 'id'
  console.log(name); // 'limo'
}
相關文章
相關標籤/搜索