What is Symbol? Why is there such a thing? The following article will introduce you to the Symbol type in JavaScript and talk about how to use it. I hope it will be helpful to you!
Symbol (symbol) is a new data type added 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. [Related recommendations: javascript learning tutorial]
symbols Need to be initialized using the Symbol() function. Because symbols themselves are primitive types, the typeof operator returns symbol on symbols.
let sym = Symbol(); console.log(typeof sym); // symbol
The 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, Then use the 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 it based on the parameters passed in. Symbol.for() has created the same instance. If it exists, reuse it. If not, create a new one.
let fooGlobalSymbol = Symbol.for("foo"); // 创建新符号 let otherFooGlobalSymbol = Symbol.for("foo"); // 重用已有符号 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 be equal to other instances just because the parameters you pass in are the same. However, 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"); // 创建新符号 let otherFooGlobalSymbol = Symbol.for("foo"); // 重用已有符号 console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
The attributes in objects are generally in the form of strings, but they can also be used Symbol instances are used 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", }; // 这样也可以: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 If symbol does not declare a variable for reception at the beginning, then all symbol attributes of the object must be traversed to find the corresponding attribute 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, override 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 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. Used by the for-await-of statement." In other words, this symbol represents a function that implements the asynchronous iterator API.
This property is defined on the prototype of Function. 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); // true
If you redefine the Symbol.hasInstance property of a function, you can let 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 true, means the object should flatten its array elements using Array.prototype.concat()". The Array.prototype.concat() method in ES6 will Select 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.
false: Add an entire object to the array true: Add an entire object Add the 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-of statement"
该属性会返回一个 Generator 函数,for of 就会依次的去调用 next()方法,这就是为什么 for of 可以使用在某些对象身上。
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
根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法用正则表达式去匹配字符串。由 String.prototype.match()方法使用”。
String.prototype.match()方法会使用以 Symbol.match 为键的函数来对正则表达式求值。所以更改一个正则表达式的 Symbol.match 属性,可以让 String.prototype.match()得到你想要的值
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
这个符号作为一个属性表示“一个正则表达式方法,该方法返回字符串中 匹配正则表达式的索引。由 String.prototype.search()方法使用”
这个符号作为一个属性表示“一个函数值,该函数作为创建派生对象的构 造函数”。
这个符号作为一个属性表示“一个正则表达式方法,该方法在匹配正则表 达式的索引位置拆分字符串。由 String.prototype.split()方法使用”。
这个符号作为一个属性表示“一个方法,该方法将对象转换为相应的原始 值。由 ToPrimitive 抽象操作使用”
这个符号作为一个属性表示“一个字符串,该字符串用于创建对象的默认 字符串描述。由内置方法 Object.prototype.toString()使用”
这个符号作为一个属性表示“一个对象,该对象所有的以及继承的属性, 都会从关联对象的 with 环境绑定中排除
更多编程相关知识,请访问:编程视频!!
The above is the detailed content of Why is there Symbol type? how to use?. For more information, please follow other related articles on the PHP Chinese website!