This is the sixth day of my participation in Gwen Challenge

Symbol

A symbol is a primitive data type. Unlike Number, String, or Boolean, it has no literal syntax.

Common symbol creation

const syb = Symbol(a);const syb1 = Symbol("The description of the sign.");
Copy the code

There is no literal syntax for creating literals, only the Symbol method.

Symbol cannot be called as a constructor; new Symbol() returns an error.

You can pass in a String argument that describes the symbol instance. A non-string type is converted to String.

The characteristics of

  1. There are no literals.

  2. Typeof Symbol() returns “Symbol”.

  3. Symbol instances are unique and immutable.

    const syb = Symbol(a);const syb1 = Symbol(a); syb ! == syb1Copy the code
  4. Symbols can exist as property names of objects, called symbolic properties.

    • Developers can carefully design these properties so that they cannot be accessed by the outside world in the usual way (private properties). Using a closure, the symbol instance is the property name of the object. If you cannot access the symbol instance, you cannot access the property through the property name of the object. [] is the calculation attribute name, which can put expressions.

      var person = (function() {
          const name = Symbol("Private attribute _ Name");
          return {
              [name]: "Herb".getName() {
                  return this[name]; }}} ())Copy the code
    • Symbolic properties are not enumerable, so they cannot be read in for-in loops or object. keys.

    • Object. GetOwnPropertyNames although can get their own all the property name cannot be enumerated, but still can’t read symbol attribute names.

    • Object. GetOwnPropertyDescriptor access to an Object of a certain attributes and symbol of the descriptor Object (the attribute must belong to the Object directly).

    • New Object ES6 getOwnPropertySymbols method, can read symbol attribute name, returns an array.

  5. Symbols cannot be converted implicitly, and therefore cannot be used for mathematical operations, String concatenation, or other implicit conversion scenarios, but symbols can be explicitly converted to strings through the String conversion function (which actually calls the toString() method).

    var syb = Symbol("Symbol");
    var sybStr = String(syb);
    String(syb) == syb.toString()
    Copy the code
  6. If you want to wrap objects with symbols, you can borrow the Object() function

    var sybObj = Object(Symbol("Sign object"));
    typeof sybObj == "object"
    sybObj.constructor
    ƒ Symbol()
    sybObj instanceof Symbol
    // true
    Copy the code

Shared symbols

  1. for

    Create shared symbols with symbol.for (” Symbol description “). You can use the same Symbol as the property name for different objects.

    Once created, the symbol is stored in the global symbol registry, with the symbol description as the key and the symbol instance as the name.

    When we call symbol.for (” find “), we first check the registry to see if the Symbol is described (” find “). If not, we create a Symbol(” find “). If so, we return the name based on the key.

    let foo = Symbol.for("foo");
    let foo1 = Symbol.for("foo");
    foo == foo1
    
    let bar = Symbol("bar");
    let bar1 = Symbol.for("bar"); bar ! == bar1let unDes = Symbol.for();
    // Symbol(undefined)
    Copy the code

    The internal implementation might look something like this:

    const symbolFor = (() = > {
        const global = {};
        return des= > {
            if(!global[des]) {
                global[des] = Symbol(des);
            }
            return global[des];
        }
    })();
    Copy the code

    The global symbol registry is formed by saving global variables with immediate functions.

    Any value passed as an argument (other than the Symbol instance) to symbol.for () is converted to a string. TypeError is raised if it is a symbol instance, presumably with special handling.

  2. keyFor

    KeyFor () queries the global registry, accepts a Symbol instance, returns the corresponding key (Symbol description) in the global Symbol registry, and returns undefined if it is not a global Symbol.

    If the argument is not a symbol, TypeError is raised.

Famous symbol

ES6 introduces a number of commonly used built-in symbols to expose language behavior.

  1. Symbol.hasInstance

    This symbol represents, as a property, a method that determines whether a constructor object recognizes an object as an instance of it.

    This property is defined on the Function prototype and can be called on all functions and classes.

    In ES6, the instanceof operator uses the symbol.hasinstance function to determine the relationship.

    class Person{
        constructor(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex; }}Copy the code

    var p = new Person("Herb".18."Male");
    var isPersonInstance = p instanceof Person;
    // true
    Copy the code

    P in the prototype chain of Person, the implicit prototype of P __proto__ is the prototype of Person. P.__proto__ == Person. Prototype results in true.

    isPersonInstance = Person[Symbol.hasInstance](p);
    // true
    Copy the code

    The two ways are equivalent.


    Person instanceof Function
    // true
    Person[Symbol.hasInstance] === Function.prototype[Symbol.hasInstance] 
    // true
    Copy the code

    The symbol.hasinstance method is defined on the prototype of Function, since the Person constructor is created by Function, so Person inherits Function.

    I found the Symbol. HasInstance method on Person and its prototype chain. Because I didn’t override it on Person, I found function.prototype.

    let propertyObj = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance);
    // writable: false
    Copy the code

    Looking at its property descriptor, Symbol. HasInstance cannot be overwritten.

    So you can’t use:

    Person[Symbol.hasInstance] = function() {
        console.log("Override Function. Prototype method");
        return false;
    }
    Copy the code

    The Symbol. HasInstance attribute will be searched on the prototype chain. Finally, it is found on the Function prototype.

    So you can write a static method directly into the Person class.

    var obj = {};
    Object.prototype.name = "herb";
    Object.defineProperty(Object.prototype, "name", { writable: false });
    obj.name = "ice";
    obj.name   // "herb"
    obj        / / {}
    Copy the code

    Properties cannot be modified. And it won’t be on OBJ.

    var obj = {}
    Object.prototype.name = "herb";
    obj.name = "ice";
    obj.name          // "ice"
    obj               // { name: "ice" }
    Copy the code

    Properties can be added to objects without setting them to be writable.


    class Person{
        constructor(name, age, sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        // The Symbol. HasInstance method is defined on the prototype of the Person class
        [Symbol.hasInstance]() {
            console.log("Person rewriting method on Function prototype");
            return false;
        }
        // Overrides the function on the class, is the class static method
        static [Symbol.hasInstance]() {
            console.log("Person rewriting method on Function prototype");
            return false; }}Copy the code

    p instanceof Person
    Person[Symbol.hasInstance](p)
    // Person overwrites the method on the Function prototype
    // false
    Copy the code

    Using static method writing form of class, can be overridden.

    Object.defineProperty(Person, Symbol.hasInstance, {
        value: function() {
            console.log("DefineProperty rewrite")
            return false; }})/ / defineProperty rewritten
    // false
    Copy the code

    You can also define properties of an object, that is, properties of a class (static).

    Well-known symbols allow us to be more involved in the internal implementation of the JS language.

  2. Symbol.toPrimitive

    This symbol represents, as a property, a method that converts an object to its corresponding raw value.

    This function changes the default behavior by defining a function on the symbol.toprimitive property of an instance.

    class Team{
        constructor(teamName, teamNum) {
            this.teamName = teamName;
            this.teamNum = teamNum;
            this[Symbol.toPrimitive] = function(type){
                switch(type) {    
                    case "number":
                        return this.teamNum;
                    case "default":
                    case "string":
                        return this.teamName; }}}}Copy the code

    const team = new Team(G.i. Joe.4);
    Number(team)     / / 4
    +team            / / 4
    team + 1         // "g.I. Joe 1"
    team + "nb"      // "special forces nb"
    team * 5		 / / 20
    String(team)	 // "special forces"
    Copy the code

    When performing math operations, type is number.

    When plus signs and strings are present, type is default.

    When the String() transformation function is called, type is String.

    We have to do a little bit more research here.

    Put this property in the instance and it will be created multiple times. You can also put it on the prototype chain.


    class Team{
        constructor(teamName, teamNum) {
            this.teamName = teamName;
            this.teamNum = teamNum;
        }
        [Symbol.toPrimitive](type) {
            switch(type) {    
                case "number":
                    return this.teamNum;
                case "default":
                case "string":
                    return this.teamName; }}}Copy the code

    This will affect team.prototype however.

    String(Team.prototype)
    // "undefined"
    Copy the code
  3. Symbol.toStringTag

    This symbol represents a string as an attribute and is used to create the default string description of the object.

    By the method of built-in Object. The prototype. The toString () is used.

    When the Object identifier is obtained through the toString() method, the instance identifier specified by symbol.toStringTag is retrieved, which defaults to “Object”.

    class Bar {
        constructor() {
            this[Symbol.toStringTag] = "Bar";
        }
        // [Symbol.toStringTag] = "Bar"
    }
    var bar = new Bar();
    bar.toString();
    // "[object Bar]"
    Copy the code

    You can write it as an instance property or a static property of a class.