天天看點

ES6中的Symbol

title: ES6中的Symbol

  • Symbol

    函數前不能使用

    new

    指令,否則會報錯。這是因為生成的 Symbol 是一個原始類型的值,不是對象。也就是說,由于 Symbol 值不是對象,是以不能添加屬性。基本上,它是一種類似于字元串的資料類型。
  • Symbol

    函數可以接受一個字元串作為參數,表示對 Symbol 執行個體的描述,主要是為了在控制台顯示,或者轉為字元串時,比較容易區分。
  • Symbol

    函數的參數隻是表示對目前 Symbol 值的描述,是以相同參數的

    Symbol

    函數的傳回值是不相等的。
  • 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

      值作為對象的屬性名時不能用點運算符:
      const mySymbol = Symbol();
      const a = {};
      
      a.mySymbol = 'Hello!';
      a[mySymbol] // undefined
      a['mySymbol'] // "Hello!"
                 
  • 在對象内部使用

    Symbol

    值定義屬性時,

    Symbol

    值必須放在方括号中
    • let s = Symbol();
      
      let obj = {
        [s]: function (arg) { ... }	// 或是對象增強寫法: [s](arg) { ... }
      };
      
      obj[s](123);
                 

一. 屬性名的周遊

作為屬性名的

Symbol

值和其他字元串類型的鍵不同,無法通過

for...in

for...of

循環中,也不會被

Object.keys()

Object.getOwnPropertyNames()

JSON.stringify()

傳回。

它通過

Object.getOwnPropertySymbols

方法傳回指定對象的所有

Symbol

屬性名(傳回一個數組)

故通過此方法可以為對象定義一些非私有的、但又希望隻用于内部的方法

let size = Symbol('size');

class Collection {
  constructor() {
    this[size] = 0;
  }

  add(item) {
    this[this[size]] = item;
    this[size]++;
  }

  static sizeOf(instance) {
    return instance[size];
  }
}

let x = new Collection();
Collection.sizeOf(x) // 0

x.add('foo');
Collection.sizeOf(x) // 1

Object.keys(x) // ['0']
Object.getOwnPropertyNames(x) // ['0']
Object.getOwnPropertySymbols(x) // [Symbol(size)]
           

另一個新的 API,

Reflect.ownKeys

方法可以傳回所有類型的鍵名,包括正常鍵名和 Symbol 鍵名。

二. 子產品的Singleton模式

Singleton

模式指的是調用一個類,任何時候傳回的都是同一個執行個體。

對于

node

來講,子產品檔案可以看作是一個類,為了保證每次執行此子產品檔案傳回的都是同一個執行個體,我們常把執行個體放到頂層對象

global

// mod.js
function A() {
  this.foo = 'hello';
}

if (!global._foo) {
  global._foo = new A();
}

module.exports = global._foo;
           

然後加載上邊的

mod.js

const a = require('./mod.js');
console.log(a.foo);
           

但問題是我們必須令引用

mod.js

的諸多檔案既可以使用,又無法修改

為防止此情況的發生,我們可以使用

Symbol

// mod.js
const FOO_KEY = Symbol('foo');

function A() {
  this.foo = 'hello';
}

if (!global[FOO_KEY]) {
  global[FOO_KEY] = new A();
}

module.exports = global[FOO_KEY];
           

若鍵名使用

Symbol

方法生成,那麼外部将無法引用這個值,自然也無法改寫。

繼續閱讀