In JavaScript, the object key can only be in either string or symbol.
A symbol represents a unique identifier
To create a symbol, the syntax is shown below:
id = Symbol()
To create a symbol with a description (symbol-name), the syntax is shown below:
id = Symbol("description")
The description is just a label that is unique to an object.
It is important to note that symbols with the same description are still different.
See the example below:
const id1 = Symbol("description");
const id2 = Symbol("description");
console.log(id1 === id2); // false
It is also important to note that symbols do not allow auto-conversion (coercion) to string.
See the example below:
const id3 = Symbol("description");
alert(id3); // TypeError...
To do the conversion, use the toString()
function on it.
See the example below:
const id4 = Symbol("id");
alert(typeof id4.toString); // string
Alternatively, we can use the id.description
to show the description only.
let id5 = Symbol("id");
alert(id5.description, toString id5.description); // id string
Hidden Properties
Symbols allow us to create hidden properties of an object. See the example below:
const person = { // belongs to another code
name: "Bello"
};
let id = Symbol("id");
person[id] = 4; // added id key to user object
alert( person[id] ); // 4 => accessed data by the symbol as the key
The code above shows that a symbol cannot be accessed accidentally by any part of your code.
If a string is used in place of a symbol, the last string "id" will be overridden (overwritten) by any other previous string id from our script or another JavaScript library script.
See the example below:
const person = { name: "John" };
// my script uses "id" property
person.id = "id value before the last script";
// library script uses the "id" property
person.id = "id value in last script" // overwritten by another script!
console.log(person.id); // id value in last script
Symbol id as key
To use a symbol as a key in an object literal, the square bracket must be used around it.
const id = Symbol("id");
const user = {
name: "John",
[id]: 639 // not "id": 639
};
Cloning symbol keys
The for...in skips any symbol key in an object. See the example below:
const id = Symbol("id");
const user = {
name: "Bello",
age: 27,
[id]: 396
};
for (let key in user) {
console.log(key); // name, age => no symbols
}
// Object.keys(user) also skips them.
The Object.assign
copies both string and symbol properties.
See the example below:
const id = Symbol("id");
const user = {
name: "Bello",
age: 27,
[id]: 396
};
let clone = Object.assign({}, user);
alert( clone[id] ); // 396
Global Symbol Registry
Symbols are always different by default even if they have the same description, but sometimes we want to use the same-named symbol of the same entities anyway in a program.
To achieve that, the Symbol.for(key)
is used to create a global symbol registry for repeated access by the same name to return exactly the same symbol.
See the example below:
const id1 = Symbol.for("id"); // if the symbol did not exist, it is created
const id2 = Symbol.for("id");
console.log( id1 === id2); // true => the same symbol
Symbols inside the registry are called global symbols.
Symbol.keyFor
The reverse of Symbol.for is Symbol.keyFor, it returns a name by a global symbol.
See the example below:
// get symbol by name
const sym1 = Symbol.for("id1");
const sym2 = Symbol.for("id2");
// get name by symbol
console.log( Symbol.keyFor(sym1) ); // id1
console.log( Symbol.keyFor(sym2) ); // id2
The
Symbol.keyFor
internally uses the global symbol registry to look up the key for the symbol. If the symbol is not global, it returnsundefined
See the example below:
const globalSymbol = Symbol.for("globalName");
const localSymbol = Symbol("localName");
console.log( Symbol.keyFor(globalSymbol) ); // globalName => global symbol
console.log( Symbol.keyFor(localSymbol) ); // undefined => not global
console.log( localSymbol.description ); // localName
System Symbols
Internally, there are different JavaScript System Symbols. Below is a few of them.
- Symbol.hasInstance
- Symbol.isConcatSpreadable
- Symbol.iterator
- Symbol.toPrimitive
Check out the full list on MDN