How to quickly get started with VUE3.0: Learn
Symbol (symbol) is a new data type in ES6. Symbols are primitive values (the underlying data type), and Symbol instances are unique and immutable. It is generated because it is used to uniquely mark and then be used as object attributes in non-string form. It is to ensure that object attributes use unique identifiers and there is no danger of attribute conflicts.
symbols need to be initialized using the Symbol() function. Because symbols themselves are primitive types, the typeof operator returns symbol for symbols.
let sym = Symbol(); console.log(typeof sym); // symbol
Symbol() function can receive a string parameter to describe, and then you can use this string to debug the code. But it is worth noting that even if multiple Symbol() functions accept the same parameters, their values are not equal.
let genericSymbol = Symbol(); let otherGenericSymbol = Symbol(); let fooSymbol = Symbol("foo"); let otherFooSymbol = Symbol("foo"); console.log(genericSymbol == otherGenericSymbol); // false console.log(fooSymbol == otherFooSymbol); // false
If you need to use the same Symbol instance in multiple places in the code, you can pass in a string and then use Symbol.for( ) method to create a reusable Symbol, similar to the singleton mode. When using Symbol.for() for the first time, it will globally search whether to use Symbol.for() to create it based on the parameters passed in. The same instance has been passed, if it exists, reuse it, if not, create
a new one let fooGlobalSymbol = Symbol.for("foo"); // Create a new symbol let otherFooGlobalSymbol = Symbol.for("foo"); // Reuse it Signed console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
The difference between the instance created by Symbol.for() and the instance created by Symbol(): The instance created by Symbol() is always unique and will not change because of the The input parameters are the same and are equal to other instances, but the instances created by Symbol.for() will be equal if the parameters are the same, because they will share the same Symbol instance
let fooSymbol = Symbol("foo"); let otherFooSymbol = Symbol("foo"); console.log(fooSymbol == otherFooSymbol); // false let fooGlobalSymbol = Symbol.for("foo"); // Create a new symbol let otherFooGlobalSymbol = Symbol.for("foo"); // Reuse an existing symbol console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
The attributes in objects are generally in the form of strings, but in fact you can also use Symbol instances as attributes. The advantage of this is that your new attributes will not overwrite any previous attributes
let s1 = Symbol ("foo"), s2 = Symbol("bar"), s3 = Symbol("baz"), s4 = Symbol("qux"); let o = { [s1]: "foo val", }; // This also works: o[s1] = 'foo val'; console.log(o); // {Symbol(foo): foo val} Object.defineProperty(o, s2, { value: "bar val" }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val} Object.defineProperties(o, { [s3]: { value: "baz val" }, [s4]: { value: "qux val" }, }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val, // Symbol(baz): baz val, Symbol(qux): qux val}
Note: When creating a Symbol instance as an object attribute, if you change the symbol without declaring a variable to receive it at the beginning, you must subsequently traverse all the symbols of the object. property to find the corresponding property key:
let o = { [Symbol("foo")]: "foo val", [Symbol("bar")]: "bar val", }; console.log(o); // {Symbol(foo): "foo val", Symbol(bar): "bar val"} let barSymbol = Object.getOwnPropertySymbols(o).find(symbol => symbol.toString().match(/bar/)); console.log(barSymbol); // Symbol(bar)
ES6 also introduces a number of commonly used built-in symbols (well-known symbols) to expose the internal behavior of the language. Developers can directly access, rewrite or simulate these behaviors. If these default attributes are modified, the final execution results of some operations can be changed. For example, a for-of loop will use the Symbol.iterator property on the relevant object, so you can change the behavior of for-of when iterating the object by redefining the value of Symbol.iterator on the custom object.
is actually a Generator that returns a Promise, generally used with for await of
According to the ECMAScript specification, this symbol as an attribute represents "a method that returns the object's default AsyncIterator. By for-await -of statement using ". In other words, this symbol represents a function that implements the asynchronous iterator API.
This property is defined on the Function prototype. We all know that the instanceof operator can be used to determine whether an object instance belongs to a certain constructor. The principle is that the instanceof operator will use the Symbol.hasInstance function to determine the relationship
function Foo() {} let f = new Foo(); console.log(f instanceof Foo); // true class Bar {} let b = new Bar(); console.log(b instanceof Bar); // trueIf
you redefine a function's Symbol.hasInstance property, you can have the instanceof method return something unexpected
class Bar {} class Baz extends Bar { static [Symbol.hasInstance]() { return false; } } let b = new Baz(); console.log(Bar[Symbol.hasInstance](b)); // true console.log(b instanceof Bar); // true console.log(Baz[Symbol.hasInstance](b)); // false console.log(b instanceof Baz); // false
This property is defined on the prototype of Array
. According to the ECMAScript specification, this symbol as a property represents "a Boolean value. If it is true, it means that the object should use Array. prototype.concat() flattens its array elements". The Array.prototype.concat() method in ES6 will choose how to splice an array-like (pseudo-array) object into an array instance based on the received object type. So modifying the value of Symbol.isConcatSpreadable can modify this behavior.
is false: add an entire object to the array true: add an entire pair to the array
let initial = ["foo"]; let array = ["bar"]; console.log(array[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(array)); // ['foo', 'bar'] array[Symbol.isConcatSpreadable] = false; console.log(initial.concat(array)); // ['foo', Array(1)] let arrayLikeObject = { length: 1, 0: "baz" }; console.log(arrayLikeObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(arrayLikeObject)); // ['foo', {...}] arrayLikeObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(arrayLikeObject)); // ['foo', 'baz'] let otherObject = new Set().add("qux"); console.log(otherObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(otherObject)); // ['foo', Set(1)] otherObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(otherObject)); // ['foo']
According to the ECMAScript specification, this symbol as an attribute represents "a method that returns the object's default iterator. Used by for- The of statement uses "
This attribute will return a Generator function, and for of will call the next() method in turn. This is why for of can be used on certain objects.
class Emitter { constructor(max) { this.max = max; this.idx = 0; } *[Symbol.iterator]() { while (this.idx < this.max) { yield this.idx++; } } } function count() { let emitter = new Emitter(5); for (const x of emitter) { console.log(x); } } count(); // 0 // 1 // 2 // 3 // 4
According to the ECMAScript specification, this symbol as an attribute represents "a regular expression method that uses a regular expression to match a string. Used by the String.prototype.match() method."
The String.prototype.match() method evaluates a regular expression using a function keyed by Symbol.match. So changing the Symbol.match attribute of a regular expression allows String.prototype.match() to get the value you want
console.log(RegExp.prototype[Symbol.match]); // ƒ [Symbol.match]() { [native code] } console.log("foobar".match(/bar/)); // ["bar", index: 3, input: "foobar", groups: undefined] class FooMatcher { static [Symbol.match](target) { return target.includes("foo"); } } console.log("foobar".match(FooMatcher)); // true console.log("barbaz".match(FooMatcher)); // false class StringMatcher { constructor(str) { this.str = str; } [Symbol.match](target) { return target.includes(this.str); } } console.log("foobar".match(new StringMatcher("foo"))); // true console.log("barbaz".match(new StringMatcher("qux"))); // false
This symbol as an attribute represents "a regular expression method that returns the matching regular expression in the string Index of the formula. Used by the String.prototype.search() method"
This symbol as an attribute represents "a function value that serves as a constructor for creating derived objects."
This symbol as an attribute represents "a regular expression method that splits a string at the index position that matches the regular expression. Used by the String.prototype.split() method."
This symbol as an attribute represents "a method that converts an object to the corresponding primitive value. Used by the ToPrimitive abstract operation"
This symbol as an attribute represents "a string that String is used to create the default string description of the object. Used by the built-in method Object.prototype.toString()."
This symbol represents an object as a property, and all of the object's and inherited properties will be derived from the associated Excluded from object's with environment binding