famous symbols
A famous symbol is an unregistered symbol that is the same in different domains. If we were to list famous symbols, they would be:
-
Symbol.iterator
-
Symbol.toStringTag
-
Symbol.toPrimitive
-
Symbol.asyncIterator
-
Symbol.hasInstance
-
Symbol.isConcatSpreadable
-
Symbol.species
-
Symbol.match
-
Symbol.matchall
-
Symbol.replace
-
Symbol.search
-
Symbol.split
-
Symbol.unscopables
-
Symbol.dispose
Let's look at some examples to understand its usefulness.
Symbol.iterator
Symbol.iterator
: This symbol is used to define the default iterator for objects. It is used to for-of
implement iteration over objects in a loop, or with the spread operator.
const obj = { a: 1, b: 2, c: 3 };
obj[Symbol.iterator] = function*() {
for (const key of Object.keys(this)) {
yield [key, this[key]];
}
};
for (const [key, value] of obj) {
console.log(`${key}: ${value}`);
}
Symbol.toStringTag
Symbol.toStringTag
: This symbol is used to specify Object.prototype.toString
the string value returned when calling a method in order to provide a custom string representation for the object.
class MyClass {
static [Symbol.toStringTag] = 'MyClass';
}
const myInstance = new MyClass();
console.log(myInstance.toString()); // outputs '[object MyClass]'
Symbol.toPrimitive
Symbol.toPrimitive
: This symbol is used to specify the behavior of an object when implicitly calling valueOf
methods toString
. You can use it to provide custom string and numeric representations for objects.
class Life {
valueOf() {
return 42;
}
[Symbol.toPrimitive](hint) {
switch (hint) {
case "number":
return this.valueOf();
case "string":
return "Forty Two";
case "default":
return true;
}
}
}
const myLife = new Life();
console.log(+myLife); // 42
console.log(`${myLife}`); // "Forty Two"
console.log(myLife + 0); // 42
Symbol.asyncIterator
Symbol.asyncIterator
: This symbol is used to define an asynchronous iterator for an object. You can use this to enable asynchronous iteration of objects.
class MyAsyncIterable {
async *[Symbol.asyncIterator]() {
for (let i = 0; i < 5; i++) {
await new Promise(resolve => setTimeout(resolve, 1000));
yield i;
}
}
}
(async () => {
for await (const value of new MyAsyncIterable()) {
console.log(value);
}
})();
// Output after one second:
// 0
// Output after two seconds:
// 1
// Output after three seconds:
// 2
// Output after four seconds:
// 3
// Output after five seconds:
// 4
Symbol.hasInstance
Symbol.hasInstance
: This symbol is used to confirm whether an object is an instance of the constructor. It can be used to change instanceof
the behavior of operators.
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
const arr = [1, 2, 3];
console.log(arr instanceof MyArray); // true
Symbol.isConcatSpreadable
Symbol.isConcatSpreadable
: This symbol is used to determine whether an object should be expanded when connected to other objects. It can be used to change Array.prototype.concat
the behavior of a method.
const arr1 = [1, 2, 3];
const spreadable = { [Symbol.isConcatSpreadable]: true, 0: 4, 1: 5, 2: 6, length: 3 };
console.log([].concat(arr1, spreadable)); // [1, 2, 3, 4, 5, 6]
Symbol.species
Symbol.species
: This symbol is used to specify the constructor to be used when creating a derived object. It can be used to customize the behavior of built-in methods that create new objects.
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
const myArray = new MyArray(1, 2, 3);
const mappedArray = myArray.map(x => x * 2);
console.log(mappedArray instanceof MyArray); // false
console.log(mappedArray instanceof Array); // true
PS: This feature may be removed in the future.
Symbol.match
Symbol.match
: This symbol is used String.prototype.match
to determine the value to search for when using a method. It can be used to change the behavior of RegExp
object -like match
methods.
const myRegex = /test/;
'/test/'.startsWith(myRegex); // Throws TypeError
const re = /foo/;
re[Symbol.match] = false;
"/foo/".startsWith(re); // true
"/bar/".endsWith(re); // false
PS: The existence of this symbol is what marks an object as a "regex".
const myRegex = /foo/g;
const str = 'How many foos in the the foo foo bar?';
for (result of myRegex[Symbol.matchAll](str)) {
console.log(result); // we will get the matches
}
Symbol.replace
Symbol.replace
: This symbol is used to String.prototype.replace
determine the replacement value when using the method. It can be used to change the behavior of RegExp
object -like replace
methods.
const customReplace = str => str.replace(/\d+/g, match => `-${match}-`);
const customString = {
[Symbol.replace]: customReplace
};
const originalString = "foo123bar456baz";
const result = originalString.replace(customString, '*');
console.log(result); // outputs "foo-123-bar-456-baz"
Symbol.split
Symbol.split
: This symbol is used to String.prototype.split
determine the delimiter value when using the method. It can be used to change the behavior of RegExp
object -like split
methods.
const { Symbol } = require('es6-symbol');
const customSplit = str => str.split(/\d+/);
const customRegExp = {
[Symbol.split]: customSplit
};
const string = "foo123bar456baz";
string.split(customRegExp); // outputs [ 'foo', 'bar', 'baz' ]
Symbol.unscopables
Symbol.unscopables
: This symbol is used to determine with
which object properties should be excluded from the scope of the statement. It can be used to change with
the behavior of statements.
const person = {
age: 42
};
person[Symbol.unscopables] = {
age: true
};
with (person) {
console.log(age);
// Expected output: Error: age is not defined
}
Symbol.dispose
Symbol.dispose
: "Explicit resource management" refers to a system in which the user explicitly manages the life cycle of a "resource" by using imperative methods (such as Symbol.dispose) or declarative methods (such as using block-scope declarations).
{
console.log(1);
using {
[Symbol.dispose]() {
console.log(2);
}
};
console.log(3);
}
// will log 1, 3, 2
Summarize
This informative blog aims to provide an in-depth introduction to the famous symbols inherent in the JavaScript language, such as Symbol.iterator
, Symbol.toStringTag
and Symbol.for
. These symbols represent complex and versatile tools that can be used to enhance and tune the behavior of your code. A thorough understanding of the available symbols in a JavaScript environment is key to developing high-performance, maintainable, and scalable applications. Therefore, during the conceptualization and implementation stages of the project, it is recommended to evaluate the feasibility of incorporating these symbols to make the code more concise and elegant and achieve the desired effect.
Article reprinted from: chuckQu
Original link: https://www.cnblogs.com/chuckQu/p/17271182.html