Javascript Symbol

Overview

Before introduction of symbol in ES6, It was very hard to define the private variables. Developers mostly used to do a workaround of using closure to make variables private. But now symbols can be used to create private object members. Symbols are added as a primitive type just like strings, numbers, booleans, null, and undefined.

Syntax

We can create symbols in javascript by using Symbol() function.

let name = Symbol();
let details = {};
details[name] = 'Prashant Yadav';
console.log(details[name]);
//"Prashant Yadav"

let fullName = symbol()

As symbols are primitive values we cannot use them as a constructor. Calling Symbol with new keyword like new Symbol() will throw an error.

Symbol function also accepts an argument which is used to describe the symbol.

let name = Symbol('Full Name');
let details = {};
details[name] = 'Prashant Yadav';

console.log(details[name]);
//"Prashant Yadav"

console.log(name);
//Symbol(Full Name)

The description is stored internally and is read whenever the Symbol.toString() method is called implicitly or explicitly.

Symbols are always unique. Even if declared with same description.

let details = {};
let firstName = Symbol('Full Name');
details[firstName] = 'Prashant';

console.log(details[firstName]);
//"Prashant"

let secondName = Symbol('Full Name');
details[secondName] = 'Yadav';

console.log(details[secondName]);
//"Yadav"

console.log(firstName == secondName);
//false

As we can see we have created two different Symbols with same description still they are not same.


Different ways to define Symbol in Javascript

We can use Symbol where ever we use a computed property name.

As a dynamic object property

let firstName = Symbol('First Name');
let lastName = Symbol('Last Name');
let details = {
   [firstName] = 'Prashant'
   [lastName] = 'Yadav'
};

console.log(details[firstName]);
//Prashant

console.log(details[lastName]);
//Yadav

Using object.defineProperty()

let firstName = Symbol('First Name');
let lastName = Symbol('Last Name');
let details = {};

Object.defineProperty(details, firstName, {
  value: 'Prashant',
  writable: false
});

Object.defineProperty(details, lastName, {
  value: 'Yadav',
  writable: false
});

console.log(details[firstName]);
//Prashant

console.log(details[lastName]);
//Yadav

Using object.defineProperties()

let firstName = Symbol('First Name');
let lastName = Symbol('Last Name');
let details = {};

Object.defineProperties(details, {
  [firstName]: {
    value: 'Prashant',
    writable: true
  },
  [lastName]: {
    value: 'Yadav',
    writable: false
  }
});

console.log(details[firstName]);
//Prashant

console.log(details[lastName]);
//Yadav

Using Symbol globally in javascript

We may some times want to use share the same symbol with the different parts of our code. It is difficult to keep track of the symbol across large code base.

In order to make our work easy ES6 provides us a function called Symbol.for() which stores the Symbol in global registry. It accepts a single parameter description Symbol.for('name') and checks if a Symbol with same description exits or not. If it exists then it returns the existing else it will create a new one.

let details = {};

let firstName = Symbol.for('name');
details[firstName] = 'Prashant';
console.log(details[firstName]);
//'Prashant'

let lastName = Symbol.for('name');
details[lastName] = 'Yadav';
console.log(details[lastName]);
//'Yadav'

console.log(firstName); //Symbol(name)
console.log(lastName);  //Symbol(name)

console.log(firstName === lastName);
//true

Checking current Symbol being used.

There is an another function Symbol.keyFor(Symbol) which is used to check the current Symbol being used in global registry. It takes the Symbol as input and returns the description of the Symbol.

let firstName = Symbol.for('name');
let lastName = Symbol.for('name');
let middleName = Symbol('abc');

console.log(Symbol.keyFor(firstName));
//"name"

console.log(Symbol.keyFor(lastName));
//"name"

console.log(Symbol.keyFor(middleName));
//undefined

As Symbol('abc') is not stored in the global registry. It returns undefined.

Retrieving Symbol Properties

We know that we can use Symbol as object property but we cannot retrieve it using existing object methods like Object.keys() and Object.getOwnPropertyNames() as they return all enumerable property names.

let office = {
  [Symbol("Tom")] : "CEO",
  [Symbol("Mark")] : "CTO",
  [Symbol("Mark")] : "CIO",
}

for(person in office) {
  console.log(person);
}

//undefined

As Symbol is not enumerable. ES6 provides us a function which we can use to retrieve Symbols. Object.getOwnPropertySymbols() returns an array of own property Symbols.

let office = {
  [Symbol("Tom")] : "CEO",
  [Symbol("Mark")] : "CTO",
  [Symbol("Mark")] : "CIO",
}

const symbols = Object.getOwnPropertySymbols(office);
console.log(symbols);
/*
(3) [Symbol(Tom), Symbol(Mark), Symbol(Mark)]
0: Symbol(Tom)
1: Symbol(Mark)
2: Symbol(Mark)
length: 3
__proto__: Array(0)
*/

We can use this array of own property Symbols along with map to retrive all the values.

let office = {
  [Symbol("Tom")] : "CEO",
  [Symbol("Mark")] : "CTO",
  [Symbol("Mark")] : "CIO",
}

const symbols = Object.getOwnPropertySymbols(office);
const values = symbols.map(symbol => office[symbol]);

for(let value in values) {
  console.log(values[value]);
}

//CEO
//CTO
//CIO

Javascript Symbol Methods

Symbol.hasInstance

It is used by instanceOf to check the inheritance of the object.


Symbol.isConcatSpreadable

Return’s a boolean value. It is used to indicate Array.prototype.concat() that it should flatten the collection passed to it.


Symbol.iterator

Return’s an iterator.


Symbol.match

Used by String.prototype.match() to compare strings.


Symbol.replace

Used by String.prototype.replace() to replace substrings.


Symbol.search

Used by String.prototype.search() to find substrings.


Symbol.split

Used by String.prototype.split() to split string in array of characters.


Symbol.species

Constructor to create derived objects.


Symbol.toPrimitive

Returns the primitive value of the object.


Symbol.toStringTag

A string used by Object.prototype.toString() to create an object description.


Symbol.unscopables

An object whose properties are the names of object properties that should not be included in a with statement.

Leave a Reply

Your email address will not be published. Required fields are marked *