Do you know how to use JavaScript symbol types

Time:2020-9-27

Symbol type

According to the specification, the property key of an object can only be of string type or symbol type. It’s not number, it’s not Boolean, it’s only string or symbol.

So far, we’ve only seen strings. Now let’s take a look at what symbols can do for us.

Symbol

The “symbol” value represents a unique identifier.

You can use symbol() to create values of this type:

//ID is an instantiation object of the symbol
let id = Symbol();

When creating, we can give the symbol a description (also known as the symbol name), which is very useful for code debugging:

//ID is a symbol described as "Id"
let id = Symbol("id");

The symbol guarantee is unique. Even if we create many symbols with the same description, their values are different. The description is just a label and doesn’t affect anything.

For example, here are two symbols that describe the same — they are not equal:


let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false

If you’re familiar with ruby or any other language with a “symbol” – don’t be misled. JavaScript’s symbol is different.

Note: symbols are not automatically converted to strings

Most values in JavaScript support implicit conversion of strings. For example, we can alert any value that takes effect. Symbol is special, it will not be converted automatically.

For example, this alert will prompt an error:

let id = Symbol("id");
Alert (ID); // type error: unable to convert symbol value to string.

This is a kind of “language protection” against confusion, because strings and symbols are inherently different and should not be accidentally converted into another.

If we really want to display a symbol, we need to call. Tostring() on it, as follows:

let id = Symbol("id");
alert( id.toString ()); // symbol (ID), now it works

Or get it symbol.description Property, only the description is displayed:


let id = Symbol("id");
alert(id.description); // id

Hidden property

Symbol allows us to create “hidden” properties of an object that no other part of the code can accidentally access or override.

For example, if we are using user objects that belong to third-party code, we want to add some identifiers to them.

We can give them the symbol key:

Let user = {// belongs to another code
 name: "John"
};

let id = Symbol("id");

user[id] = 1;

Alert (user [ID]); // we can use symbol as the key to access the data

What are the benefits of using symbol (“Id”) on the string “Id”?

Because user belongs to another code and another code uses it to perform some operations, we should not add any fields to it, which is very unsafe. But the symbol won’t be accessed accidentally, so third-party code won’t see it, so there may not be any problem with using a symbol.
In addition, suppose another script wants to have its own identifier in the user to achieve its own purpose. This could be another JavaScript library, so scripts don’t know each other at all.

The script can then create its own symbol (“Id”) like this:


// ...
let id = Symbol("id");

user[id] = "Their id value";

There is no conflict between our identifier and their identifier, because symbols are always different, even if they have the same name.

…… But if we use the string “Id” instead of symbol for the same purpose, there will be a conflict:

let user = { name: "John" };

//Our script uses the "Id" attribute.
user.id = "Our id value";

// …… Another script also wants to use "Id" for its purpose  

user.id = "Their id value"
//Bang! ID was accidentally rewritten by another script!

Symbol in literal quantity

If we want to use a symbol in the literal {…} of an object, we need to enclose it in square brackets.

Like this:

let id = Symbol("id");

let user = {
 name: "John",
 [ID]: 123 // instead of "ID: 123"
};

This is because we need the value of the variable ID as the key, not the string “Id”.

Symbol is skipped in for.. in

Symbolic property does not participate in the for.. in loop.

For example:

let id = Symbol("id");
let user = {
 name: "John",
 age: 30,
 [id]: 123
};

for (let key in user) alert(key); // name, age (no symbols)

//Direct access using symbol task
alert( "Direct: " + user[id] );

Object.keys (user) also ignores them. This is part of the general “hidden symbolic properties” principle. If another script or library traverses our object, it won’t accidentally access the symbol properties.

contrary, Object.assign The string and symbol properties are copied at the same time:


let id = Symbol("id");
let user = {
 [id]: 123
};

let clone = Object.assign({}, user);

alert( clone[id] ); // 123

There’s no contradiction here. That’s how it’s designed. The idea here is that when we clone or merge an object, we usually want all the attributes to be copied (including symbols like ID).

Other types of property keys are forced to Strings:

We can only use string or symbol as key in object, other types will be converted to string.

For example, when used as a property key, the number 0 becomes the string “0”:

let obj = {
 0: "test" // same as "0": "test"
};

//Both alerts access the same property (number 0 is converted to the string "0")
alert( obj["0"] ); // test
Alert (obj [0]); // test (the same property)

Global symbol

As we can see, usually all symbols are different, even if they have the same name. But sometimes we want symbols with the same name to have the same entity. For example, the symbol “Id” that different parts of the application want to access refer to exactly the same properties.

To achieve this, there is a global symbol registry. We can create symbols in it and access them later, which ensures that every time a symbol with the same name is accessed, the same symbol is returned.

To read or create a symbol from the registry, use the Symbol.for (key)。

This call will check the global registry and return the symbol if there is a symbol described as key. Otherwise, a new symbol (symbol (key)) will be created and stored in the registry through the given key.

For example:

//Read from global registry
let id =  Symbol.for ("Id"); // if the symbol does not exist, create it

//Read again (possibly another location in the code)
let idAgain = Symbol.for("id");

//Same symbol
alert( id === idAgain ); // true

Symbols in the registry are called global symbols. If we want an application wide symbol, we can access it everywhere in the code – that’s what they are for.

It sounds like Ruby:

In some programming languages, such as ruby, each name has a symbol.

As we can see, the same is true of global symbols in JavaScript.

Symbol.keyFor

For global symbols, not only Symbol.for (key) return a symbol by name and a reverse call: Symbol.keyFor (sym), its role is exactly the opposite: return a name through the global symbol.

For example:

//Get symbol by name
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");

//Get name through symbol
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id

Symbol.keyFor Internally, the global symbol registry is used to find the key of the symbol. So it doesn’t apply to non global symbols. If the symbol is not global, it will not find it and return undefined.

That is, any symbol has a description attribute.

For example:

let globalSymbol = Symbol.for("name");
let localSymbol = Symbol("name");

alert(  Symbol.keyFor (globalsymbol)); // name, global symbol
alert(  Symbol.keyFor (localsymbol)); // undefined, non Global

alert( localSymbol.description ); // name

System symbol

There are many “system” symbols inside JavaScript that we can use to fine tune various aspects of objects.
They are listed in the specification of the well-known symbol table:

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.toPrimitive
  • …… wait.

For example, Symbol.toPrimitive Allows us to describe an object as a raw value transformation. We’ll see its use soon.
When we study the corresponding language features, we will gradually become familiar with other symbols.

summary

Symbol is the basic type of a unique identifier

A symbol is created using a symbol () call with an optional description (name).

Symbols always have different values, even if they have the same name. If we want symbols of the same name to be equal, we should use the global registry: Symbol.for (key) returns (if necessary, creates) a global symbol with key as its name. use Symbol.for When a symbol with the same key is called multiple times, the same symbol is returned.

Symbol has two main usage scenarios:

  • Hide object properties. If we want to add a property to an object “belonging to” another script or library, we can create a symbol and use it as the key for the property. The symbol attribute does not appear in for.. in, so it is not accidentally processed with other properties. Also, it won’t be accessed directly because the other script doesn’t have our symbol. As a result, the property is protected from accidental use or override.

So we can use the symbol attribute “secretly” to hide something in the object we need, but we can’t see it anywhere else.

  • JavaScript uses a number of system symbols that can be accessed as symbols *. We can use them to change some of the built-in behavior. For example, later in this tutorial, we will use the Symbol.iterator To iterate, use Symbol.toPrimitive To set the conversion of the original value of the object and so on.

Technically, symbols are not 100% hidden. There is a built-in method Object.getOwnPropertySymbols (obj) allows us to get all the symbols. There’s another one called Reflect.ownKeys (obj) method can return all the keys of an object, including symbol. So they’re not really hidden. However, most libraries, built-in methods, and syntax structures do not use these methods.

The above is the whole content of this article, I hope to help you in your study, and I hope you can support developeppaer more.