你需要知道的Symbols

chuck發表於2023-03-30

著名symbol

著名symbol是一個在不同領域中都相同且未註冊的symbol。如果我們要列出著名symbol,它們會是:

  • Symbol.iterator
  • Symbol.toStringTag
  • Symbol.toPrimitive
  • Symbol.asyncIterator
  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.species
  • Symbol.match
  • Symbol.matchall
  • Symbol.replace
  • Symbol.search
  • Symbol.split
  • Symbol.unscopables
  • Symbol.dispose

讓我們看一些例子來了解其有用性。

Symbol.iterator

Symbol.iterator:該symbol被用來為物件定義預設的迭代器。它被用來在for-of迴圈中實現對物件的迭代,或用於擴充套件運算子。

const obj = { a: 1, b: 2, c: 3 };

obj[Symbol.iterator] = function*() {
  for (const key of Object.keys(this)) {
    yield [key, this[key]];
  }
};

for (const [key, value] of obj) {
  console.log(`${key}: ${value}`);
}

Symbol.toStringTag

Symbol.toStringTag:該symbol被用來指定在呼叫Object.prototype.toString方法時返回的字串值,以便為物件提供自定義的字串表示形式。

class MyClass {
  static [Symbol.toStringTag] = 'MyClass';
}

const myInstance = new MyClass();

console.log(myInstance.toString()); // outputs '[object MyClass]'

Symbol.toPrimitive

Symbol.toPrimitive:該symbol被用來指定物件在隱式呼叫valueOftoString方法時的行為。可以用它來為物件提供自定義的字串和數字表示形式。

class Life {
  valueOf() {
    return 42;
  }

  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case "number":
        return this.valueOf();
      case "string":
        return "Forty Two";
      case "default":
        return true;
    }
  }
}

const myLife = new Life();
console.log(+myLife); // 42
console.log(`${myLife}`); // "Forty Two"
console.log(myLife + 0); // 42

Symbol.asyncIterator

Symbol.asyncIterator:該symbol被用來為物件定義一個非同步的迭代器。可以用它來為物件啟用非同步迭代。

class MyAsyncIterable {
  async *[Symbol.asyncIterator]() {
    for (let i = 0; i < 5; i++) {
      await new Promise(resolve => setTimeout(resolve, 1000));
      yield i;
    }
  }
}

(async () => {
  for await (const value of new MyAsyncIterable()) {
    console.log(value);
  }
})();

// Output after one second:
// 0
// Output after two seconds:
// 1
// Output after three seconds:
// 2
// Output after four seconds:
// 3
// Output after five seconds:
// 4

Symbol.hasInstance

Symbol.hasInstance:該symbol被用來確認一個物件是否是建構函式的例項。它可以用來更改instanceof運算子的行為。

class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

const arr = [1, 2, 3];
console.log(arr instanceof MyArray); // true

Symbol.isConcatSpreadable

Symbol.isConcatSpreadable:該symbol被用來確定物件在與其他物件連線時是否應該被展開。它可以用來更改Array.prototype.concat方法的行為。

const arr1 = [1, 2, 3];
const spreadable = { [Symbol.isConcatSpreadable]: true, 0: 4, 1: 5, 2: 6, length: 3 };

console.log([].concat(arr1, spreadable)); // [1, 2, 3, 4, 5, 6]

Symbol.species

Symbol.species:該symbol被用來指定建立派生物件時要使用的建構函式。它可以用來自定義建立新物件的內建方法的行為。

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

const myArray = new MyArray(1, 2, 3);
const mappedArray = myArray.map(x => x * 2);

console.log(mappedArray instanceof MyArray); // false
console.log(mappedArray instanceof Array); // true
P.S:這一功能在未來可能會被刪除。

Symbol.match

Symbol.match:該symbol被用來在使用String.prototype.match方法時確定要搜尋的值。它可以用來更改類似於RegExp物件的match方法的行為。

const myRegex = /test/;
'/test/'.startsWith(myRegex); // Throws TypeError

const re = /foo/;
re[Symbol.match] = false;
"/foo/".startsWith(re); // true
"/bar/".endsWith(re); // false

P.S: 這個symbol的存在是標誌著一個物件是"regex"的原因。

const myRegex = /foo/g;
const str = 'How many foos in the the foo foo bar?';

for (result of myRegex[Symbol.matchAll](str)) {
  console.log(result); // we will get the matches
}

Symbol.replace

Symbol.replace:該symbol被用來在使用String.prototype.replace方法時確定替換值。它可以用來更改類似於RegExp物件的replace方法的行為。

const customReplace = str => str.replace(/\d+/g, match => `-${match}-`);

const customString = {
  [Symbol.replace]: customReplace
};

const originalString = "foo123bar456baz";

const result = originalString.replace(customString, '*');

console.log(result); // outputs "foo-123-bar-456-baz"

Symbol.split

Symbol.split:該symbol被用來在使用String.prototype.split方法時確定分隔值。它可以用來更改類似於RegExp物件的split方法的行為。

const { Symbol } = require('es6-symbol');

const customSplit = str => str.split(/\d+/);

const customRegExp = {
  [Symbol.split]: customSplit
};

const string = "foo123bar456baz";

string.split(customRegExp); // outputs [ 'foo', 'bar', 'baz' ]

Symbol.unscopables

Symbol.unscopables:該symbol被用於確定應該從with語句的作用域中排除哪些物件屬性。它可以用來更改with語句的行為。

const person = {
  age: 42
};

person[Symbol.unscopables] = {
  age: true
};

with (person) {
  console.log(age);
  // Expected output: Error: age is not defined
}

Symbol.dispose

Symbol.dispose:“顯式資源管理”是指使用者透過使用命令式方法(如Symbol.dispose)或宣告式方法(如使用塊作用域宣告)顯式地管理“資源”的生命週期的系統。

{ 
  console.log(1); 
  using { 
    [Symbol.dispose]() { 
      console.log(2); 
     } 
  }; 
  console.log(3); 
}
// will log 1, 3, 2

總結

這篇資訊性的部落格旨在深入介紹JavaScript語言中固有的著名symbol,例如Symbol.iteratorSymbol.toStringTagSymbol.for。這些symbol代表著複雜而多才多藝的工具,可以用來增強和調節程式碼的行為。在JavaScript環境中全面理解可用symbol是開發高效能、可維護和可擴充套件應用程式的關鍵。因此,在專案的概念化和實施階段,建議評估將這些symbol納入其中的可行性,以使程式碼更加簡潔、優雅,達到預期的效果。

以上就是本文的全部內容,如果對你有所幫助,歡迎收藏、點贊、轉發~

相關文章