betacode

Руководство JavaScript Symbol

  1. Понятие о Symbol
  2. Symbol - Key
  3. Symbol - Enums
  4. Symbol.for(key) & Symbol.forKey(symbol)

1. Понятие о Symbol

Symbol является новым "примитивным видом данных" (Primitive data type), представленный в ECMAScript 6. До ES6 мы имели только 5 примитвных видов это Number, String, Boolean, null, undefined.
Чтобы создать Symbol вы используете следующий синтаксис:
// Create a Symbol
var mySymbol1  = Symbol();

// Create a Symbol
var mySymbol2 = Symbol("Something");
Примечание: Symbol не является классом, поэтому вы не можете создать его оператором new:
var mySymbol1 = new Simbol(); // ==> ERROR!!

var mySymbol2 = new Simbol("Something"); // ==> ERROR!!
Все примитивные виды как Number, String, Boolean, null, undefined очень ясные и явные.
  • Number: 1, 2, 3, ...
  • String: "Hello", "Bye", ...
  • Boolean: true, false
  • null
  • undefined
Symbol является абстрактным, вы не можете дотронуться до него и не можете знать его реальное значение. Symbol является абсолютно уникальным (абсолютно разный), это значит если вы создаете 2 Symbol, то они разные, даже если вы создаете 2 Symbol одним способом.
symbol-example1.js
var symbolA1 = Symbol();
var symbolA2 = Symbol();

console.log(symbolA1); // Symbol()
console.log(symbolA2); // Symbol()
console.log(symbolA1 === symbolA2); // false

var symbolB1 = Symbol("Tom");
var symbolB2 = Symbol("Tom");

console.log(symbolB1); // Symbol(Tom)
console.log(symbolB2); // Symbol(Tom)
console.log(symbolB1 === symbolB2); // false

2. Symbol - Key

Symbol можно использовать как ключ (Key) для объектов Map.
symbol-map-key-example.js
var key1 = Symbol();
var key2 = Symbol();
var key3 = Symbol("Something");

var map = new Map();

map.set(key1, "Tom");
map.set("a_string_key", "Donald");
map.set(key2, "Jerry");
map.set(key3, "Mickey");

console.log( map.get(key1));  // Tom
console.log( map.get("a_string_key")); // Donald
console.log( map.get(key2));  // Jerry
console.log( map.get(key3));  // Mickey
[Symbol]?
Symbol можно использовать как property объекта.
symbol-object-property-example.js
var prop1 = Symbol();
var prop2 = Symbol();
var prop3 = Symbol("Something");

var myObject = {
   name : "Tom",
   gender: "Male",
   [prop1]: "Something 1",
   [prop2]: "Something 2",
   [prop3]: "Something 3",
};

console.log( myObject["name"] );  // Tom
console.log( myObject["gender"] ); // Male

console.log( myObject[prop1] ); // Something 1
Symbol на самом деле полезен, чтобы вы определили metadata (метаданные) в одном объекте. Если property (объекта) является Symbol, он не будет распознан функциями, что возвращают property.
symbol-metadata-example.js
const sym = Symbol()

const foo = {
  name: 'Tom',
  age: 25,
  [sym]: 'Some Hidden Metadata'
}

let keys = Object.keys(foo) // name, age
console.log("keys: " + keys);

let propNames = Object.getOwnPropertyNames(foo) // name, age
console.log("propNames: " + propNames);

for(let val of keys) {
  console.log(foo[val]) // Tom // 25
}
Symbol Property не совсем скрыты, вы все еще можете взять список Symbol Property объекта через следующие методы:
Object.getOwnPropertySymbols(someObject);

Reflect.ownKeys(someObject);
Например:
symbol-get-props-example.js
const sym1 = Symbol();
const sym2 = Symbol("Test");

const someObject = {
  name: 'Tom',
  age: 25,
  [sym1]: 'Some Hidden Metadata 1',
  [sym2]: 'Some Hidden Metadata 2'
}

var symbolProps = Object.getOwnPropertySymbols(someObject);

console.log(symbolProps); // [ Symbol(), Symbol(Test) ]

var objKeys = Reflect.ownKeys(someObject);

console.log(objKeys); // [ 'name', 'age', Symbol(), Symbol(Test) ]

3. Symbol - Enums

В ES5 очень часто вы создаете константы (constants) для представления определенного понятия. И вид обычно использованных данных для определения константы является Number или String.
OK, например вам нужно создать 4 константы представляющие 4 сезона года, и функция getWeather(season) возвращает соответствующую погоду в переданный сезон.
var SEASON_SPRING = "SPRING";
var SEASON_SUMMER = "SUMMER";
var SEASON_AUTUMN = "AUTUMN";
var SEASON_WINTER = "WINTER";

function getWeather(season)  {
   switch(season) {
      case SEASON_SPRING:
         return "warm";
      case SEASON_SUMMER:
         return "hot";
      case SEASON_AUTUMN:
         return "cool";
      case SEASON_WINTER:
          return "cold";
      default:
         throw 'Invalid season';
   }
}

console.log( getWeather(SEASON_SPRING) ); // warm
Иногда вы используете неправильную константу в коде, но все же принимается программой. Это опасно.
var SEASON_SPRING = "SPRING";
var SEASON_SUMMER = "SUMMER";
var SEASON_AUTUMN = "AUTUMN";
var SEASON_WINTER = "WINTER";

var FRAMEWORK_SPRING = "SPRING";
var FRAMEWORK_STRUTS = "STRUTS";


var weather1 = getWeather( SEASON_SPRING ); // warm

// (***)
var weather2 = getWeather( FRAMEWORK_SPRING ); // warm
Использование Symbol для определения константы является хорошим решением для вас в этом случае. Константы вида Symbol представляют определенное понятие названное Enums (Похоже на понятие Enums в Java).
symbol-enums-example.js
// Season Enums:
const SEASON_SPRING = Symbol();
const SEASON_SUMMER = Symbol();
const SEASON_AUTUMN = Symbol();
const SEASON_WINTER = Symbol();

// Framework Enums:
const FRAMEWORK_SPRING = Symbol();
const FRAMEWORK_STRUTS = Symbol();

function getWeather(season)  { // Season Enums
   switch(season) {
      case SEASON_SPRING:
         return "warm";
      case SEASON_SUMMER:
         return "hot";
      case SEASON_AUTUMN:
         return "cool";
      case SEASON_WINTER:
          return "cold";
      default:
         throw 'Invalid season';
   }
}

console.log( getWeather(SEASON_SPRING) ); // warm

console.log( getWeather(FRAMEWORK_SPRING) ); // Throw Error: Invalid season

4. Symbol.for(key) & Symbol.forKey(symbol)

Метод Symbol.for(keyName) возвращает значение как соответствующий Symbol с ключом keyName в глобальном объекте Map (Global). Если ключ keyName не существует в глобальном объекте Map, пара keyName/Symbol(keyName) будет добавлена в объект Map, и возвращает Symbol(keyName) выше.
symbol-for-example.js
const tom = Symbol.for('Tom') // If the Symbol does not exist, it's created

const tom2 = Symbol.for('Tom') // The Symbol exists, so it is returned

console.log( tom === tom2); // true
Symbol.for() & Symbol.for(undefined) одинаковые.
symbol-for-example2.js
const foo = Symbol.for();

const bar = Symbol.for(undefined);

console.log( foo === bar); // true
Если Symbol управляется на глобальном объекте Map вы можете найти его ключ используя метод Symbol.keyFor(symbol).
symbol-keyFor-example.js
const foo = Symbol.for('someKey');// This Symbol in Global Map.

const key1 = Symbol.keyFor(foo); // someKey
console.log(key1); // someKey


const bar = Symbol("Test");// This Symbol not in Global Map.

const key2 = Symbol.keyFor(bar);
console.log(key2); // undefined

Pуководства ECMAScript, Javascript

Show More