What is Symbol

  • Symbol is the new base data type in ES6, which is unique, like UUID.
  • Symbol is a function that creates Symbol data by calling the Symbol function.
  • Symbol is also a built-in object that provides a series of functions known Symbol methods to change the internal behavior of THE JS language.

The nature and use of Symbol

Example: Create Symbol data

  • Symbol is not created as a literal, nor can it be created asnew Symbol()Constructor can only be created by callingSymbol([description])Delta function, orSymbol.for()To create.

// Symbol is not allowed to be called with the new key constructor
new Symbol(a)// Uncaught TypeError: Symbol is not a constructor

// Create Symbol data with no description
let symbol1 = Symbol(a)// Create the Symbol data with the description
let localSymbol Symbol('desc1')

// Create Symbol data in the global environment
let globalSymbol = Symbol.for('desc1')

// The Symbol in the global registry is different from the Symbol created by the Symbol function
console.log(localSymbol === globalSymbol)
// Output: false

Copy the code

Properties: Symbol is always unique

  • Data is always unique, not only in functions, modules, and even in the window top-level scope
// Call the Symbol function to create unique Symbol data in the current environment (function scope/module scope). The toString output looks the same, but the two are not equal
let f1 = Symbol('flag')
let f2 = Symbol('flag')

console.log(f1,f2)
// Symbol(flag) Symbol(flag)

console.log(f1 === f2)
// Output: false
console.log(f1 === 'flag')
/ / output is false


// Call symbol.for (key) to create Symbol data in the global environment.
// When the method is called, the idempotent operation is performed on the key name. If the method does not exist, the idempotent operation is created, and if it does exist, the idempotent operation is returned
let lock = Symbol.for('flag')
let lockFlag = Symbol.for('flag')
console.log(lock === lockFlag)
// Output: true

The // Symbol() function is different from the Symbol data created by symbol.for ()
console.log(f1 === lock)
// Output: false

// In a global environment, if you don't want to create, just want to find, you can use symbol.keyfor ()
console.log(Symbol.keyFor('flag')) // flag
console.log(Symbol.keyFor('test')) // undefined but not created
Copy the code

Example: Use Symbol to define constants

  • Since Symbol’s properties are unique, we can use symbols as constants.
  • We used to define constants like this:
const FRUIT =  {
  APPLE: 'APPLE'.BANANA: 'BANANA'.STRAWBERRY: 'STRAWBERRY'  
} 

// We don't care what value is, we just look at key
console.log(FRUIT.APPLE)

// But if some fool adds a pineapple and writes it as an apple, the judgment will burst
const FRUIT =  {
  APPLE: 'APPLE'.BANANA: 'BANANA'.STRAWBERRY: 'STRAWBERRY'.PINEAPPLE: 'APPLE'  / / new
} 

// This problem can be avoided by using the Symbol definition
const FRUIT =  {
  APPLE: Symbol(),
  BANANA: Symbol(),
  STRAWBERRY: Symbol()}function translate(FRUIT_TYPE){
  switch (FRUIT_TYPE) {
    case FRUIT.APPLE:
      console.log('apple')
      break;
    case FRUIT.BANANA:
      console.log('banana')
      break;
    case FRUIT.STRAWBERRY:
      console.log('strawberry')
      break;
    default:
      console.log('Not matched')
      break;
  }
}

translate(FRUIT.APPLE)
// Output: apple
Copy the code

Example: Use Symbol to define a person’s name

  • For example, in a class, people want to use names as unique identifiers, but names cannot avoid repetition. Symbol is used to achieve this
const grade = {
  [Symbol('Lily'] : {address: 'shenzhen'.tel: '* * * * * 186 * 78'},Symbol('Annie'] : {address: 'guangzhou'.tel: '183 * * * * * * 12'
  },
  // Duplicate names are allowed
  [Symbol('Lily'] : {address: 'beijing'.tel: '172 * * * * * * 10'}},Copy the code

Features: Type judgment and type conversion of Symbol

  • Like String, Symbol can passtypeofOperator for type determination
let symbol = Symbol(a)console.log(typeof Symbol)
// Output: symbol
Copy the code
  • However, unlike String, Symbol does not perform implicit automatic type conversions, so it cannot perform String concatenation and arithmetic operations directly. However, explicit type conversions can be performed artificially, such as String, Boolean, Number, or Object
let symbolUUID = Symbol('uuid')

// String concatenation cannot be performed directly
console.log(symbolUUID + 'test') 
// TypeError: Cannot convert a Symbol value to a string

// Do not perform arithmetic directly
console.log(symbolUUID + 1) 
// TypeError: Cannot convert a Symbol value to a number

// But it can do Boolean judgment operation of ternary operation
console.log(symbolUUID ? 'true' : 'false')
// Output: true

console.log(String(symbolUUID) + 'test')
// Output: Symbol(uuid) test
// equivalent to symboluuid.tostring ()


Copy the code

Properties: Symbol can be used as the attribute key name of an object

  • According to the specification, the Symbol type can exist either as data alone or as the attribute key name of an object. In addition, the property key of an object can only be a string or Symbol. No other data type can be used as the property key, Boolean or Number.
  • But it is worth noting that the need to{[SymbolKey]: value}Array parentheses to mount.
// as the attribute name of the object
let desc = Symbol('desc')
let person = {
  name: 'huilin'.sex: 'male',
  [desc]: 'Position: Front-end Engineer'
}
Person [desc] = 'Position: front-end engineer'
console.log(person)
/ / output: {name: 'huilin, sex:' male 'Symbol (' desc') : 'position: former engineer'}

Copy the code
  • Symbol is weakly hidden as an attribute name
/* * The normal way to obtain object attributes automatically ignores the */ of the Symbol attribute's key pair
// The above example, if formatted json.stringify (), ignores Symbol
console.log(JSON.stringify(person))
// Output: {name: 'huilin',sex: 'male '}

Similarly, regular traversal operations like the for loop ignore Symbol
for(key in person){
    console.log(key)
}
// Output: name sex

// object.keys () ignores Symbol
console.log(Object.keys(person))
// Output: ['name', 'sex']

// object.getProperty () ignores Symbol
console.log(Object.getOwnPropertyNames(person))
// Output: ['name', 'sex']


/* * The method to get only the key-value pair of the Symbol attribute */
console.log(Object.getOwnPropertySymbol(person))
[Symbol(desc)]


/* * The method to get both the regular and Symbol properties */

console.log(Reflect.ownKeys(person))
['name', 'sex', Symbol(desc)]
Copy the code

Example: Simulate a private property or method of an object through Symbol

  • Using the weak hiding of the Symbol attribute name, the private attribute is simulated
// Symbol Specifies the attribute name of type
const id = Symbol(a)class User {
  constructor(idVal, name, age){
    this[id] = idVal
    this.name = name
    this.age = age
  }

  checkId(id){
    return this[id] === id
  }
}

// Private attribute, external instance cannot obtain directly
let u = new User('001'.'Jay'.40)
console.log(u.name, u.age, u[id])
// Output: Jay 40 001

// However, private attributes can be accessed through exposed methods
console.log(u.checkId('001')) // true
console.log(u.checkId('002')) // false


Copy the code

Example: Use Symbol for data collection and integration

  • Take the example of Zhang Xinxu asking about a young girl. Under normal circumstances, two objects will be merged, and the same key will be covered:
let info1 = {
  name: 'light snow'.age: 24.job: 'Front End Engineer'.desc: 'Likes going to the movies, is already seeing someone'
}

let info2 = {
  desc: 'Loves puppies, lives in nanshan, commutes by bus'
}

// Since desc is the String used as the key, the key will also be overridden
console.log(Object.assgin(info1,info2)) 
// Output: {name: 'xiaoxiao ',age: 24,job:' front-end engineer ',desc: 'Like dogs, live in Nanmountain, commute by bus '}
Copy the code
  • What if we use Symbol as the attribute key? Symbol is not overwritten
let info1 = {
  name: 'light snow'.age: 24.job: 'Front End Engineer'[Symbol('desc')]: 'Likes going to the movies, is already seeing someone'
}

let info2 = {
  [Symbol('desc')]: 'Loves puppies, lives in nanshan, commutes by bus'
}

// With Symbol as the key, the merge is retained
console.log(Object.assgin(info1,info2)) 
// output: {name: '小雪',age: 24,job: 'front end engineer ',Symbol('desc'):' likes movies, is dating ',Symbol('desc'): 'likes dogs, lives in the south, commuting '}
Copy the code
  • Symbol is more concerned with the value than the key name. It can be concluded that the characteristic of Symbol is to facilitate the collection and integration of data.
  • Take the example in real life. In the “like wall” of wechat articles, the data value is “like”, but the record will not be covered, and the user’s picture will be listed. Another example is the check-in book, the data value is the time, it is likely to be the same as a bunch of check-in time, but will not be overwritten, but listed in the records.
  • So if you go back to JavaScript syntax, you might think, well, name collisions are pretty rare, right? Is it necessary to add a Symbol? ES6 Module imports and exports can be aliased. There is also ES6 deconstruction, you can directly get the object property name into the current environment; Do you still think the chances of name conflicts are low?
  • Therefore, Symbol uses the pooling and consolidation features to facilitate downward compatibility of methods or variables with the same name when upgrading to the base framework version.

The system Symbol

  • In addition to creating their own Symbol tags, ES6 provides a set of built-in well-known Symbol tags that change the behavior of JavaScript’s underlying apis
API desc
Symbol.hasInstance This method is called when the instanceof operator is called to determine the instance
Symbol.isConcatSpreadable Determines whether to expand when array.prototype.concat () is called
Symbol.unscopables The with object specifies which attributes are excluded from the with environment when the with keyword is used
Symbol.match When str.match(obj) is executed, the property is called if it exists and the return value of the method is returned
Symbol.replace Called when str.replace(obj) is executed and returns the return value of the method
Symbol.search Called when str.search(obj) is executed and returns the return value of the method
Symbol.split Called when str.split(obj) is executed and returns the return value of the method
Symbol.iterator When the object for… Iterator is called to return the default traverser for the object
Symbol.toPrimitive Called when an object is converted to its original data type, returning the corresponding original data type of the object
Symbol.toStringTag Called when the object calls the toString method and returns the return value of the method
Symbol.species This property is used when creating derived objects

reference

  • Zhang Xinxu – Simple understanding of ES6/ES2015 Symbol() method
  • MDN – Symbol object
  • JavaScript. The info – Symbol type
  • FunDebug- Why does JavaScript have Symbol type
  • InfoQ – ES6 Symbol
  • Meteorite Hunters – Understand and use symbols in ES6