[ES6] add an original data type Symbol

preface

ES5 object attribute names are all strings, which is easy to cause attribute name conflicts. For example, if you use an object provided by others but want to add a new method (mixin mode) to this object, the name of the new method may conflict with the existing method. If there is a mechanism to ensure that the name of each attribute is unique, it will fundamentally prevent attribute name conflicts. This is why ES6 introduces symbols.

There are_data types of JavaScript:

  • Stack: original data type (Undefined, Null, Boolean, Number, String)
  • Heap: reference data types (objects, arrays, and functions)

The differences between the two types are: different storage locations;

  • The original data type is a simple data segment that is directly stored in the stack. It occupies space and is fixed. It belongs to data that is frequently used, so it is stored in the stack;
  • An object with a data type stored in the heap occupies a variable space. If it is stored in the stack, it will affect the performance of the program; The reference data type stores a pointer in the stack, which points to the starting address of the entity in the heap. When the interpreter looks for the reference value, it will first retrieve its address in the stack and obtain the address and then obtain the entity from the heap.

1, What is Symbol?

ES6 introduces a new primitive data type Symbol, which represents unique values. It is the seventh data type of JavaScript language. The first six types are: undefined, null, Boolean, String, Number, and Object.

2, Declaration method

1. the Symbol value is generated through the Symbol function.

That is to say, there are two types of attribute names of objects. One is the original string, and the other is the new Symbol type. All attribute names that belong to Symbol type are unique, which can ensure that they will not conflict with other attribute names.

let s1 = Symbol()
let s2 = Symbol()
console.log(s1)
console.log(s2)
console.log(s1 === s2) // false

Note that the new command cannot be used before the Symbol function, otherwise an error will be reported. This is because the generated Symbol is a value of the original type, not an object. That is, since the Symbol value is not an object, you cannot add attributes. Basically, it is a string like data type.

2. accept a string as a parameter

The Symbol function can accept a string as a parameter to represent the description of the Symbol instance, which is mainly used to make it easier to distinguish when it is displayed on the console or converted to a string.

//A string is acceptable as a description
let s1 = Symbol('foo')
let s2 = Symbol('foo')
console.log(s1)
console.log(s2)
console.log(s1 === s2)// false

The description string can be output through s.description:

let s = Symbol('foo')
s.name = 'kakaDorothy'
// Assignment unsuccessful
console.log(s)
// Symbol(foo)

// Output current description
console.log(s.description)
// foo

3. take object as parameter

If the parameter is an object, the toString method of the object will be called automatically to convert the object into a string, and then a Symbol value will be generated

const obj = {
    name: 'kakaDorothy',
    toString() {
    // Override toString method
        return this.name
    }
}
let s = Symbol(obj)
console.log(s)
// Symbol(kakaDorothy)

4. Symbol.for

Use symbol When for is declared, if the description is consistent, it represents the same value because symbol For will always find out whether there is a value with the same description in the global environment. If there is a value, it will point to it. Otherwise, it will be redefined (defined to the global).

let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1 === s2) // true

// Even in the local scope, symbol For will still look for in the global environment
function foo() {
    return Symbol.for('foo')
}
const x = foo()
const y = Symbol.for('foo')
console.log(x === y) // true

5. Symbol.keyFor

Returns the key of a globally registered Symbol

const s1 = Symbol('foo')
console.log(Symbol.keyFor(s1)) // undefined

const s2 = Symbol.for('foo')
console.log(Symbol.keyFor(s2)) // foo

3, Application scenarios

1. in case of duplicate names

const grade = {
    Zhang San: {address: 'xxx', tel: '111'},
    Lisi: {address: 'yyy', tel: '222'},
    Lisi: {address: 'zzz', tel: '333'},
}
console.log(grade)
// Zhangsan: {address: "xxx", tel: "111"}
// Lisi: {address: "zzz", tel: "333"}
// The last Lisi will cover the second Lisi

const stu1 = 'Lisi'
const stu2 = 'Lisi'
const grade = {
    [stu1]: {address: 'yyy', tel: '222'},
    [stu2]: {address: 'zzz', tel: '333'},
}
console.log(grade)
//Lisi: {address: "zzz", tel: "333"}
//The key is the same and will still be overwritten

Using Symbol, the value declared by Symbol is unique and at different addresses in memory:

const stu1 = Symbol('Lisi')
const stu2 = Symbol('Lisi')
const grade = {
    [stu1]: {address: 'yyy', tel: '222'},
    [stu2]: {address: 'zzz', tel: '333'},
}
console.log(grade)
//Lisi: {address: "yyy", tel: "222"}
//Lisi: {address: "zzz", tel: "333"}

// Get information about a specific person with the same name
console.log(grade[stu1])
console.log(grade[stu2])

2. protect attributes

const sym = Symbol('KD')
class User {
    constructor(name) {
        this.name = name
        this[sym] = 'KDKD'
    }
    getName() {
        return this.name + this[sym]
    }
}
const user = new User('Dorothy')
console.log(user.getName())
// DorothyKDKD

// for...in failed to get Symbol attribute value
for(let key in user){
    console.log(key)
    // name
}

// for...of fit object Keys failed to get the Symbol attribute value
for(let key of Object.keys(user)){
    console.log(key)
}

// Object.getOwnPropertySymbols can only get the Symbol property value, and cannot get other properties
for(let key of Object.getOwnPropertySymbols(user)){
    console.log(key)
    //Symbol(KD)
}

//Reflect.ownKeys can get all attribute values
for(let key of Reflect.ownKeys(user)){
    console.log(key)
    // name Symbol(KD)
}

3. eliminate magic strings

When a string appears many times in the code, it will form a strong coupling, which is called magic string.

function getArea(shape) {
    let area = 0
    switch (shape) {
        case 'Triangle':
            area = 1
            break
        case 'Circle':
            area = 2
            break
    }
    return area
}
console.log(getArea('Triangle'))

Use Symbol elimination:

const shapeType = { 
// The specific value of the attribute is not important
    triangle: Symbol(),
    circle: Symbol()
}
function getArea(shape) {
    let area = 0
    switch (shape) {
        case shapeType.triangle:
            area = 1
            break
        case shapeType.circle:
            area = 2
            break
    }
    return area
}
console.log(getArea(shapeType.triangle))

Reference link: https://es6.ruanyifeng.com/#docs/symbol

Tags: Front-end Javascript ECMAScript programming language

Posted by Trent Hatred on Thu, 28 Jul 2022 03:09:47 +0930