preface

In the Es6 Symbol (number, Boolean, NULL,undefined, string); Symbol (number, Boolean,null,undefined, string) There are only a handful of application scenarios involved.

Often in the interview, repeatedly uncomfortable. Let’s take a look at this data type

Specific problems to be solved

In Es5, object attribute names are strings, and when an object’s attribute name is duplicated, the latter tends to override the former.

Using Symbol can ensure that the name of each attribute is unique, which is equivalent to generating a unique identifier ID, thus fundamentally preventing attribute name conflicts

Symbol type

Symbol is a new feature introduced by the Es6 specification. It represents unique values and is classified as the seventh data type of the JS language. It is generated by the symbol function

Create a Symbol instance using the Symbol() function

let s1 = Symbol();
console.log(typeof s1); //symbol
console.log(Object.prototype.toString.call(s1)); // [object Symbol]
Copy the code

In the example above, typeof is used to check the type. It returns Symbol instead of string,object, etc

In Es5, we extended the Symbol type to the string type for the property names of objects, meaning that there are now two types of property names for objects

  • String type
  • Symboltype

Pay attention to

The new keyword cannot be used before the Symbol function, or an error will be reported, because the generated Symbol is a primitive value, not an object

Because it is not an object, it cannot add attributes. It is a string-like data type, which can be interpreted as an additional extension of the string type

The Symbol function accepts a string as an argument, which is a description of the Symbol instance, primarily for display on the console

The Symbol description is optional and is used only for debugging purposes or for converting to a string to distinguish, not to access the Symbol itself

Using Symbol().description returns the description of the Symbol() instance, if any, and undefined if none

Description is a static attribute of Symbol

Attribute overwriting occurs when using a string to define a property name of an object, but does not occur when using the Symbol type. The property name of an object is unique. Each call to Symbol() generates a unique identifier, even if Symbol() is used. The generated instance has the same description, but they are still not equal, always returning false as shown in the code below

let s1 = Symbol('itclanCoder'); // Defines an S1 variable, which is of type Symbol(), and receives an itclanCoder string as an instance of the Symbollet s2 = Symbol('itclanCoder'); // instantiate an s2,Symbol() typeconsole.log(s1.description); // itclanCoder
console.log(s1.description); // itclanCoder
console.log(s1 === s2); // false
Copy the code

It can be seen from the comparison result in line 5 that S1 and S2 are two different symbols. Here, symbols are allowed to accept a parameter. If no parameter is added, both symbols will be output in the console

What if you want to use the same Symbol value? In Es6, a symbol.for () method is provided that can be implemented, which takes a string as an argument and searches for a Symbol value named with that argument

If so, the Symbol value is returned, otherwise a new Symbol value named with the string is created and registered in the global environment

let s1 = Symbol.for('itclanCoder');
let s2 = Symbol.for('itclanCoder');
console.log(s1 === s2); // true
Copy the code

In the example code above,s1 and s2 are both values instantiated by Symbol, but they are both generated by the symbol. for method and point to the same value, Dietan

  • SymbolSymbol.forThe difference between

To compare

2. Both generate new symbols. Symbol() does not. Instead of returning a new Symbol type value each time it is called, symbol.for () checks to see if the given key already exists and creates a new Symbol value if it does not

Calling Symbol. For (‘itclanCoder’)100 times will return the same Symbol, but calling Symbol(‘itclanCoder’)100 times will return 100 different symbols

Symbol.for("itclanCoder") === Symbol.for("itclanCoder") / /true

Symbol("itclanCoder") === Symbol("itclanCoder") / /false
Copy the code

In the above code, since the Symbol() notation has no registration mechanism, each call returns a different value, which creates a new space in stack memory each time

It is also possible to check for global registration by returning the key of a registered Symbol type value using the symbol.keyfor () method

let s1 = Symbol.for("itclan");
console.log(Symbol.keyFor(s1)) // "itclan"

let s2 = Symbol("itclan");
console.log(Symbol.keyFor(s2)) // undefined
 Copy the code

In the above code, s2 belongs to an unregistered Symbol value, so undefined is returned

Pay attention to

Symbol.for() is the name registered for the Symbol value, and is used throughout the global scope

function foo() {
  return Symbol.for('itclan');
}

const x = foo();
const y = Symbol.for('itclan'); console.log(x === y); // true Copy the code

In the code above, symbol.for (‘itclan’) is run inside the function, but the resulting Symbol value is registered globally. So, running symbol. for(‘itclan’) a second time gets the Symbol value

  • Application scenarios:Symbol.for()

This global logging feature can be used to fetch the same value from different iframe fire service workers

In front-end development, iframes are sometimes used, but iframes are isolated from each other. If you want to obtain the same data from different iframes, this Symbol. For () is useful

See the sample code below

let iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);

iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo') / /true
Copy the code

In the code above, the Symbol value generated by the iframe window is available on the main page and is available throughout the global scope

Symbol Application Scenario

  • Application Scenario 1- UseSymbolAs the object property name (key)

Prior to Es6, it was common to define or access attributes of objects using strings, as shown in the code below

let web = {
    site: "http://itclan.cn".    name: "itclanCoder"
}
console.log(web['site']); // http://itclan.cn
console.log(web['name']); // itclanCoder Copy the code

Access the properties of a variable object, except through the object. In addition to the property name, it can be accessed through the object [‘ property name ‘], which overrides the former if the same property is present in an object

Since the value of the Symbol function is not equal each time it is called, this means that the Symbol value can be used as an identifier for the property name of the object, ensuring that no property with the same name will occur

Useful when an object is made up of multiple modules, use Symbol to place a key that has been accidentally overwritten or overwritten

Symbol can be used to define and access object attributes

See the sample code below

const PERSON_NAME = Symbol();
const PERSON_AGE = Symbol();

let person = {
    [PERSON_NAME]: "A trail of essays."
}  person[PERSON_AGE] = 20;  Console. log(person[PERSON_NAME]) //console.log(person[PERSON_AGE]) // 20 Copy the code

In the example code above, the Symbol types PERSON_NAME and PERSON_AGE were created using Symbol, but this caused some problems in actual development

After you use Symbol as the Object’s property key, you want to iterate over the Object, so use Object.keys(),for.. in,for.. Of the Object. GetOwnPropertyNames (), JSON. Stringify () enumeration Object attribute names

You will find that using Symbol brings up a very unpleasant reality, as shown in the sample code below

let person = {
   [Symbol('name')]: 'Essay Trail'.   age: 20,
   job: 'Engineer'
}
console.log(Object.keys(person)) // ["age"."job"] for(var i in person) {  console.log(i); // age job }  Object.getOwnPropertyNames(person) // ["age"."job"] JSON.stringify(person); // "{"age": 20."job":"Engineer"}" Copy the code

Keys (),for.. keys(),for… in,for.. Of, to enumerate

Nor does it contain the attribute set Object itself. The getOwnPropertyName (), the method is unable to get to

Using this feature, we can use Symbol to define properties that do not require external manipulation or access

In this way, when we define the data object of the interface, we can decide which attributes of the object, and the internal private operation and external public operation become controllable, more convenient

Properties of objects defined as symbols cannot be obtained using conventional methods. In Es6, an API for Symbols is provided

Use Object. GetOwnPropertySymbols () method, which can get all the Symbol of specified Object attribute name, this method returns an array

Its members are all Symbol values used as attribute names for the current object

let person = {
   [Symbol('name')]: 'Essay Trail'.   age: 20,
   job: 'Engineer'
}
 // Use the Object APIObject.getOwnPropertySymbols(person) // [Symbol(name)]  Copy the code

Below is Object. GetOwnPropertySymbols () method and the for.. In circulation, the Object. Comparing getOwnPropertyNames method example

const person = {};
const name = Symbol('name');

person[name] = "A trail of essays."

for(let i in person) { console.log(i); // There is no output}  Object.getOwnPropertyNames(person); / / []Object.getOwnPropertySymbols(person); // [Symbol('name')] Copy the code

In the above code, use for… In circulation and the Object. GetOwnPropertyNames () methods are not Symbol key name, you need to use the Object. The getOwnPropertySymbols () method.

If you want to retrieve all attributes, you can use a new API where the reflect.ownkeys () method returns all types of key names, including regular and Symbol

let person = {
  [Symbol('name')]: "Chuan chuan".  enum: 2,
  nonEnum: 3
};
 Reflect.ownKeys(person) // ["enum"."nonEnum", Symbol(name)] Copy the code

Because the Symbol value is used as the key name, it is not used by the normal method (for.. in,for.. Of). We can use this feature to protect private attributes by defining methods for objects that are not private but that we want to use only internally

  • Application Scenario 2: Use Symbol to define private attributes/methods of a class

JavaScript is a weakly typed language. Weak does not mean that the language is weak, but that its types are not mandatory, and it does not have the access control keyword private of object-oriented languages such as Java. All properties and methods defined on a class are publicly accessible, although there are some new keywords in TypeScript that address this issue

Sometimes, properties and methods defined on a class are publicly accessible, causing some confusion

The private properties and methods of the Symbol class become the implementation

The following example code

let size = Symbol('size'); // This declaration defines a size variable. The type is Symbol() and the type description is size
The class {// class keyword defines a Collection class  constructor() {// The constructor functionthis[size] = 0; // Privatize a size attribute on the current class }  Add (item) {// a method under the Collection class this[this[size]] = item;  this[size]++;  }  Static sizeOf(instance) {// Static property return instance[size];  } }  letx = new Collection(); // instantiate the x objectCollection.sizeOf(x) // 0  x.add('foo'); // Call the methodCollection.sizeOf(x) // 1  Object.keys(x) // ['0'] Object.getOwnPropertyNames(x) // ['0'] Object.getOwnPropertySymbols(x) // [Symbol(size)] Copy the code

The above code, the Object the size attribute is a Symbol of x value, so the Object. The keys (x), Object. GetOwnPropertyNames (x) can get it. This creates the effect of a non-private internal approach

  • Application Scenario 3- Modular mechanism

Combined with Symbol and modularization mechanism, the class’s private attributes and methods are perfectly realized, as shown in the following code in file A. js

const PASSWORD = Symbol(); // Define a PASSWORD variable of type Symbol
class Login() {// class keyword declares a Login classConstructor (username, password) {// Initialize attributes within the constructor function    this.username = username;
 this[PASSWORD] = password;  }   checkPassword(pwd) {  return this[PASSWORD] === pwd;  }  } export default Login; Copy the code

In file B.js

import Login from './a'

const login = new Login('itclanCoder'.'123456'); // Instantiate a login object
login.checkPassword('123456'); // true
login.PASSWORD; // Cannot be accessedlogin[PASSWORD]; // Cannot be accessedlogin['PASSWORD'] // Cannot be accessed Copy the code

Because the PASSWORD constant defined by Symbol is defined in the A. js module, external modules cannot obtain this Symbol, cannot reference this value externally, cannot rewrite, and cannot create an identical Symbol again

Because Symbol is unique

In the A.js module, the Symbol type of the PASSWORD can only be used internally in the current module file (A.js), so class attributes defined using it cannot be accessed outside the module

This has the effect of privatization

  • Application Scenario 4- UseSymbolInstead of constant

When React is used to manage public data state with Redux,reducer is a pure function that returns the latest state to the store. The result is determined by action and state

Action is an object with a specific type type value. If you’ve written a few lines of Redux code, you’ll often see that you split the action and define the type of the event action as a constant

const CHANGE_INPUT_VALUE = 'CHANGE_INPUT_VALUE'; // Listen for constant values in the input boxconst ADD_INPUT_CONTENT = 'ADD_INPUT_CONTENT'; // Add a listconst DELETE_LIST = 'DELETE_LIST'; // Delete the list
function reducer(state, action) {
 const newState = JSON.parse(JSON.stringify(state));  switch(action.type) {  case CHANGE_INPUT_VALUE:  // ...  case ADD_INPUT_CONTENT:  // ...  case DELETE_LIST;  // ...  default:  return state;  }  } Copy the code

This code is common in Redux. It takes the type value of the action object and defines a constant store to represent a business logic. You usually want these constants to be unique

I often get very upset when I take the type value.

Now that we have Symbol, let me rewrite it so that we can do this

const CHANGE_INPUT_VALUE = Symbol()
const ADD_INPUT_CONTENT = Symbol();
const DELETE_LIST = Symbol()

function reducer(state, action) {
 const newState = JSON.parse(JSON.stringify(state));  switch(action.type) {  case CHANGE_INPUT_VALUE:  // ...  case ADD_INPUT_CONTENT:  // ...  case DELETE_LIST;  // ...  default:  return state;  }  } Copy the code

Defining a string constant through Symbol ensures that the values of the three constants are unique

To highlight

  • The most important advantage of using the Symbol value for constants is that no other value can have the same value. This ensures that constants are unique and, therefore, ensures that the above switch statement works the way you want it to

  • When the Symbol value is used as the property name, the property is public, not private

  • Application scenario 5- Register and obtain the global ‘Symbol

Using the Symbol() function to define the generated Symbol instance is unique in the browser window

However, if the application involves multiple Windows, it is most common to embed iframes in each page window and fetch the same common data source from each iframe page

Using Symbol() is not an option if the symbols used in each window are the same

Because the Symbol instances created with it in different Windows are always unique, we need to maintain a shared Symbol value across all of these Windows.

In this case, we need to use another API to create or obtain the Symbol. That is symbol.for (), which registers or obtains a global inter-window Symbol instance, which is a static method of Symbol

This has been mentioned in front of once, this is still a little bit useful, so in mention of a mouth

See the sample code below

let gs1 = Symbol.for('global_symbol_1'// Register a global Symbollet gs2 = Symbol.for('global_symbol_1'// Get the global Symbol
console.log(gs1 === gs2 ) // true
Copy the code

The Symbol string instantiated by symbol.for () is unique not only in the current window, but also in all other global Windows, as long as the description is the same

This feature, if you create symbols that are available across files, or even across domains (each window has its own global scope), you can use symbol.for () to fetch the same value

That is, using symbol.for (), values of Symbol type can be shared globally

Matters needing attention

  • SymbolValue cannot be evaluated with other types of values – an error is reported
let symItclan = Symbol('itclan');

console.log("Host" + symItclan)
The console. The log (` master station${symItclan}`) // Uncaught TypeError: Cannot convert a Symbol value to a string
Copy the code
  • SymbolYou can display converted strings
let SyItclanCoder = Symbol('https://coder.itclan.cn');

console.log(String(SyItclanCoder)) // Symbol(https://coder.itclan.cn)
console.log(SyItclanCoder.toString()) // Symbol(https://coder.itclan.cn)
Copy the code
  • SymbolValues can be converted to Booleans, but not numeric values
let sym = Symbol();
console.log(Boolean(sym)) // true
console.log(! sym) //false

if (sym) {
 // ... }  Number(sym) // TypeError Cannot convert a Symbol value to a number sym + 2 // TypeError Copy the code

The Symbol cannot be converted to a number

  • SymbolFunction cannot be usednewThe command

We cannot use the new command before the Symbol function, or we will get an error. Symbol is a primitive value, not an object

  • Symbol valueThe dot operator cannot be used as the name of an object property

When the Symbol value is the attribute name of an object, the dot operator cannot be used to access it

const username = Symbol(); const person = {}; Person. Username = 'person '; person[username]; // undefined person['username']; //Copy the code

The fourth line is undefined because the dot operator is always followed by a string, so the value that username refers to as the identifier name is not read

The resulting property name of the Person object is actually a string rather than a Symbol value

When using the Symbol type to define the attribute name inside an object, the Symbol value must be enclosed in brackets

let s = Symbol();
let obj = {
  [s]: function(arg) {
    return arg;
  }
}  obj[s]("itclanCoder") Copy the code

In the above code, if the variable s is not enclosed in brackets, the property’s key name is the string S instead of defining the Symbol type value

conclusion

This paper mainly introduces the common use of Symbol in Es6,Symbol is a new basic type, it forms the data type of string, is an additional extension of string type

Each Symbol value returned from Symbol() is unique. This ensures that each attribute name of the object is unique and resolves the problem of conflicting attribute names

The Symbol() function returns the value of a Symbol type that has static attributes (such as Symbol().description,) and static methods (symbol.for (), symbol.keyfor ()).

Of course, it also introduces some common application scenarios of Symbol, such as the property name (key) of the object, defining the private property and method of the class, replacing constants, and registering global Symbol, and some matters needing attention

So much for Symbol, we should use it more often

For more information, you can follow the wechat itclanCoder public account, a useful account that only delivers and shares enlightening wisdom to you

Understand the Symbol type in Es6