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
-
There are no literals.
-
Typeof Symbol() returns “Symbol”.
-
Symbol instances are unique and immutable.
const syb = Symbol(a);const syb1 = Symbol(a); syb ! == syb1Copy the code
-
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.
-
-
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
-
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
-
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.
-
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.
-
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.
-
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
-
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.