Руководство ECMAScript 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