Overview

ES6 introduces a new primitive data type, Symbol, which represents unique values. Its most important use case is to define unique property names for objects.

In addition to Number, String, Boolean, Object, null, and undefined, ES6 data types also include Symbol.


Basic Usage

The Symbol function cannot be used with the new command, because Symbol is a primitive data type, not an object. It can accept a string as a parameter to provide a description for the newly created Symbol, which is used for display in the console or when used as a string, to make it easier to distinguish.

let sy = Symbol("KK"); console.log(sy); // Symbol(KK) typeof(sy); // "symbol" //Values returned by Symbol() with the same parameter are not equal. let sy1 = Symbol("kk"); sy === sy1; // false

Usage Scenarios

As Property Names

Usage

Since every Symbol value is unique, using Symbol as an object's property name can ensure that property names do not conflict.

let sy = Symbol("key1"); //Syntax 1 let syObject = {}; syObject[sy] = "kk"; console.log(syObject); // {Symbol(key1): "kk"} //Syntax 2 let syObject = { [sy]: "kk" }; console.log(syObject); // {Symbol(key1): "kk"} //Syntax 3 let syObject = {}; Object.defineProperty(syObject, sy, {value: "kk"}); console.log(syObject); // {Symbol(key1): "kk"}

When Symbol is used as an object property name, the dot operator cannot be used; square brackets must be used. Because what follows the dot operator is a string, what is accessed is the string sy property, not the Symbol-value sy property.

let syObject = {}; syObject[sy] = "kk"; syObject[sy]; // "kk" syObject.sy; // undefined

Points to Note

When a Symbol value is used as a property name, that property is public, not private, and can be accessed outside the class. However, it will not appear in for...in or for...of loops, and will not be returned by Object.keys() or Object.getOwnPropertyNames(). To read an object's Symbol properties, you can get them through Object.getOwnPropertySymbols() and Reflect.ownKeys().

let syObject = {}; syObject[sy] = "kk"; console.log(syObject); for (let i in syObject) { console.log(i); } //No output Object.keys(syObject); // [] Object.getOwnPropertySymbols(syObject); // [Symbol(key1)] Reflect.ownKeys(syObject); // [Symbol(key1)]

Defining Constants

In ES5, strings are used to represent constants. For example:

const COLOR_RED = "red";
const COLOR_YELLOW = "yellow";
const COLOR_BLUE = "blue";

But using strings cannot guarantee that constants are unique, which can cause some problems:

const COLOR_RED = "red"; const COLOR_YELLOW = "yellow"; const COLOR_BLUE = "blue"; const MY_BLUE = "blue"; function ColorException(message) { this.message = message; this.name = "ColorException"; } function getConstantName(color) { switch (color) { case COLOR_RED : return "COLOR_RED"; case COLOR_YELLOW : return "COLOR_YELLOW "; case COLOR_BLUE: return "COLOR_BLUE"; case MY_BLUE: return "MY_BLUE"; default: throw new ColorException("Can't find this color"); } } try { var color = "green"; //green throws an exception var colorName = getConstantName(color); } catch (e) { var colorName = "unknown"; console.log(e.message, e.name); //Pass the exception object to error handling }

But using Symbol to define constants can ensure that the values of this group of constants are all different. Use Symbol to modify the above example.

const COLOR_RED = Symbol("red"); const COLOR_YELLOW = Symbol("yellow"); const COLOR_BLUE = Symbol("blue"); function ColorException(message) { this.message = message; this.name = "ColorException"; } function getConstantName(color) { switch (color) { case COLOR_RED : return "COLOR_RED"; case COLOR_YELLOW : return "COLOR_YELLOW "; case COLOR_BLUE: return "COLOR_BLUE"; default: throw new ColorException("Can't find this color"); } } try { var color = "green"; //green throws an exception var colorName = getConstantName(color); } catch (e) { var colorName = "unknown"; console.log(e.message, e.name); //Pass the exception object to error handling }

Symbol values are unique, so there will be no constants with the same value, which ensures the switch statement executes as the code intends.

Symbol.for()

Symbol.for() is similar to the singleton pattern. First, it searches globally among registered Symbols to see if there is a Symbol value with that string parameter as its name. If yes, it returns that Symbol value; if not, it creates a new Symbol value with the string parameter as its name, registers it in the global environment for future searches.

let yellow = Symbol("Yellow"); let yellow1 = Symbol.for("Yellow"); yellow === yellow1; // false let yellow2 = Symbol.for("Yellow"); yellow1 === yellow2; // true

Symbol.keyFor()

Symbol.keyFor() returns the key of a registered Symbol value, which is used to check whether a Symbol value with that string parameter as its name has been registered.

let yellow1 = Symbol.for("Yellow"); Symbol.keyFor(yellow1); // "Yellow"