ECMAScript Symbols Tutorial (ES6)

View more Tutorials:

1- Concept of Symbol

Symbol is a new "primitive data type", introduced in ECMAScript 6. Before ES6 we have only five primitive types: NumberStringBooleannullundefined.
To create a  Symbol, you use the following syntax:
// Create a Symbol
var mySymbol1  = Symbol();

// Create a Symbol
var mySymbol2 = Symbol("Something");
Note: The  Symbol is not a class, so you can not create it with the new operator :
var mySymbol1 = new Simbol(); // ==> ERROR!!

var mySymbol2 = new Simbol("Something"); // ==> ERROR!!
All primitive types such as  Number, String, Boolean, null, undefined are very clear and explicit.
  • Number: 1, 2, 3, ...
  • String: "Hello", "Bye", ...
  • Boolean: true, false
  • null
  • undefined
Symbol is an abstract. You can neither touch it nor know what its actual value is. The   Symbol is completely unique (completely different), which means if you create two Symbols, they are different, even if you create two Symbols in the same way.
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 can be used as a Key for Map objects.   
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 can be used as a property of an object.
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
The Symbol is really useful for you to define  metadata in an object. If the  property (of the object) is a  Symbol, it will not be recognized by the functions that return properties.
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
}
The  Symbol Properties are not completely hidden. you can still take a list of  Symbol Properties of an object through the following methods:
Object.getOwnPropertySymbols(someObject);

Reflect.ownKeys(someObject);
 
Example:
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

In the  ES5, you frequently have to create constants to represent a concept and the data usually used to define a constant is  Number or  String.
OK, for example, you need to create four constants to represent the four seasons of a year, and the getWeather(season) function returns the weather that corresponds to the season passed.
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
Sometimes, you use constants wrongly in code but  still accepted by the program. This is dangerous.
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
Using Symbol to define constants is a good solution for you in this case. The constants with the Symbol type represent a specific concept called Enums (similar to the Enums concept in 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)

The  Symbol.for(keyName) method returns a value as a  Symbol corresponding to  keyName in a Global  Map object. If the  keyName doesn't exist in the Global  Map object, a pair of  keyName/Symbol(keyName) will be added to the  Map object and returns the above  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) are the same.
symbol-for-example2.js
const foo = Symbol.for();

const bar = Symbol.for(undefined);

console.log( foo === bar); // true
If a Symbol is managed on the Global  Map object, you can find its key using the  Symbol.keyFor(symbol) method.
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

View more Tutorials: