A, Symbol type
Symbol is a new basic data type in ES6. It belongs to the primitive value and represents unique and immutable.
Two, basic usage
- Initialize using the Symbol() function. Since it is of primitive type, Typeof returns Symbol directly
let sym = Symbol(a);console.log(typeof sym); // symbol
Copy the code
- Initialize the passable parameter, such as Symbol(‘hello’), then hello will be used as the Symbol description, for easier debugging in the future display
let sym1 = Symbol(a);console.log(sym1); // Symbol()
let sym2 = Symbol('this is sym2');
console.log(sym2); // Symbol(this is sym2)
Copy the code
- Variables that initialize the same parameter through Symbol() will not be equal. A call to Symbol() will give a new Symbol, regardless of whether the parameters are the same
let sym1 = Symbol(a);let sym2 = Symbol(a);console.log(sym1 == sym2); // false
let sym3 = Symbol('foo');
let sym4 = Symbol('foo');
console.log(sym3 == sym4); // false
Copy the code
- The Symbol() function cannot be used as a constructor with the new keyword to avoid wrapping objects like instances of Boolean, String, or Number
// 1. Instantiate examples
let myBoolean = new Boolean(a);console.log(typeof myBoolean); // "object"
let myString = new String(a);console.log(typeof myString); // "object"
let myNumber = new Number(a);console.log(typeof myNumber); // "object"
let mySymbol = new Symbol(a);// TypeError: Symbol is not a constructor
// 2. Wrap the object example
let myBoolean = new Boolean(a);let myString = new String(a);let myNumber = new Number(a);let mySymbol = Symbol(a); myBoolean.add =() = >{};
myString.add = () = >{};
myNumber.add = () = >{};
mySymbol.add = () = >{};
console.log(myBoolean.add);/ / () = > {}
console.log(myString.add);/ / () = > {}
console.log(myNumber.add);/ / () = > {}
console.log(mySymbol.add);// undefind
// 3
let mySymbol = Object(Symbol());
mySymbol.add = () = >{};
console.log(mySymbol.add);/ / () = > {}
Copy the code
- Global symbol registry
- Each time Symbol() is initialized, a new Symbol is generated
- When symbol.for () is initialized, it can pass string arguments and check whether the registry has corresponding symbols. If not, it is stored directly in the registry. The next time symbol.for () is called and the parameters are consistent, the symbols that exist in the registry are returned directly.
let sym1 = Symbol.for('foo'); // Create a new symbol let sym2 = Symbol.for('foo'); // Reuse existing symbols console.log(sym1 === sym2); // true console.log(Symbol('foo') = = =Symbol('foo')); // false console.log(Symbol('foo') = = =Symbol.for('foo')); // false Copy the code
- Symbol.keyfor () queries the registry with the global Symbol, which is created using symbol.for ()
// Create a global symbol
let sym1 = Symbol.for('foo');
console.log(Symbol.keyFor(s1)); // foo
// Create a normal symbol
let sym2 = Symbol('bar');
console.log(Symbol.keyFor(sym2)); // undefined
Copy the code
We use Symbol as the attribute of the object.
// 1
let s1 = Symbol('1'),
s2 = Symbol('2'),
s3 = Symbol('3'),
s4 = Symbol('4'),
s5 = Symbol('5');
// 2. Multiple assignment methods, consistent with common object attributes
let o = {
[s1]: 's1'.num: 1.str: 'hello'
}
o[s2] = 's2'
Object.defineProperty(o, s3, { value: 's3' });
Object.defineProperties(o, {
[s4]: { value: 's4' },
[s5]: { value: 's5'}});console.log(o); // {num: 1, str: 'hello', Symbol(1): 's1', Symbol(2): 's2', Symbol(3): 's3', Symbol(4): 's4', Symbol(5): 's5',}
The getOwnPropertyNames and getOwnPropertySymbols methods are mutually exclusive
console.log(Object.getOwnPropertyNames(o)); // ['num', 'str']
console.log(Object.getOwnPropertySymbols(o)); // [Symbol(1), Symbol(2), Symbol(3), Symbol(4), Symbol(5)]
// 4. Get all attributes on the object itself (normal attributes + symbol attributes)
console.log(Object.getOwnPropertyDescriptors(o)); / / {num: {... }, STR: {... }, Symbol (1) : {... }, Symbol (2) : {... }, Symbol (3) : {... },... }
console.log(Reflect.ownKeys(o)); // ['num', 'str', Symbol(1), Symbol(2), Symbol(3), Symbol(4), Symbol(5)]
Copy the code
4. Common built-in symbols
ECMAScript 6 introduces a number of commonly used built-in well-known symbols
- The purpose is to expose behavior within the language that developers can directly access, rewrite, or emulate.
- The built-in symbols exist as string properties of the Symbol factory function [e.g. Symbol. Iterator].
- All built-in symbolic properties are not writable, enumerable, or configurable.
1. Related to traversal (symbol.asynciterator & symbol.iterator)
- Symbol.asyncIterator represents a function that implements the asynchronous iterator API and is used by for-await-of loops to perform asynchronous iterations
- PS: ES2018 specification defined, only supported in the latest version of the browser
class Emitter {
constructor(max) {
this.max = max;
this.asyncIndex = 0;
}
async* [Symbol.asyncIterator]() {
while (this.asyncIndex < this.max) {
yield new Promise((resolve) = > resolve(this.asyncIndex++)); }}}let emitter = new Emitter(5);
for await (const x of emitter) {
console.log(x);
}
Copy the code
- Iterator represents a function that implements the Iterator API. The for-of loop is used to perform iteration operations
- Objects that can be iterated with for-of either implement themselves or have a function with a key name of [symbol.iterator] on the prototype that by default returns an object with an implementation of the next function, such as a Generator.
// 1. Not implemented [symbol.iterator]
let obj = {};
Uncaught TypeError: obj is not iterable
for(const x of obj) {
console.log(x);
}
// 2. Implement [symbol.iterator]
let obj = {
[Symbol.iterator]: function* () {
let i = 0
while (i < 5) {
yieldi++; }}}for (const x of obj) {
console.log(x); // 0 1 2 3 4
}
Copy the code
2. Instanceof related (Symblo hasInstance | Symbol. The species)
- The instanceof operator can be used to determine whether an object instance has an archetype on its archetype chain.
- Symblo.hasInstance as a property represents “a method that determines whether a constructor object recognizes an object as an instanceof it, used by the instanceof operator.
// 1
class Foo {}
let f = new Foo();
console.log(f instanceof Foo) // true
// 2. Check by [Symbol. HasInstance]
class Foo {}
let f = new Foo();
console.log(Foo[Symbol.hasInstance]) ƒ [Symbol. HasInstance]() {[native code]}
console.log(Foo[Symbol.hasInstance](f)) // true
// 3. Customize the return value of instanceof
class Foo {
static [Symbol.hasInstance] = function () {
return false; }}let f = new Foo();
console.log(f instanceof Foo); // false
Copy the code
- Symbol.species represents a function value as an attribute that serves as a constructor for creating derived objects.
class Arr1 extends Array {}
class Arr2 extends Array {
static get [Symbol.species]() {
return Array}}let arr1 = new Arr1();
arr1 = arr1.concat('arr111');
console.log(arr1 instanceof Arr1); // true
console.log(arr1 instanceof Array); // true
let arr2 = new Arr2();
arr2 = arr2.concat('arr222');
console.log(arr2 instanceof Arr2); // false
console.log(arr2 instanceof Array); // true
Copy the code
(3) related to the array (Symbol. IsConcatSpreadable)
- *Symbol. IsConcatSpreadable said a Boolean value, if it is true, means that the object should be used Array. The prototype. The concat () draw the Array (| | pseudo Array) elements.
// 1. Use array.prototype.concat normally
let arr1 = [1.2];
let arr2 = [3.4];
// Direct access gets undefinded, but the merge result is flattened, so it can be assumed that it needs to be flattened by default
console.log(arr2[Symbol.isConcatSpreadable]); // undefinded
let newArr = arr1.concat(arr2);
console.log(newArr);// [1, 2, 3, 4]
// 2. Modify elements that do not need to be flattened
let arr1 = [1.2];
let arr2 = [3.4];
console.log(arr2[Symbol.isConcatSpreadable]); // undefined
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr2[Symbol.isConcatSpreadable]); // false
let newArr = arr1.concat(arr2);
console.log(newArr); // [1, 2, Array(2)]
// 3. Pseudo-arrays also have this property
let likeObj = { length: 2.0: 'name'.1: 'age' };
let arr = [];
console.log(likeObj[Symbol.isConcatSpreadable]); // undefined
console.log(arr.concat(likeObj)); // [{ length: 1, 0: 'name', 1: 'age' }]
likeObj[Symbol.isConcatSpreadable] = true;
console.log(arr.concat(likeObj)); // ['name', 'age']
Copy the code
4. Symbol associated with the string. [match | replace | search | split]
PS: These methods are implemented by default in the regular expression regexp. protype, so most of the STRING API is used with the RegExp object. By default, even if the type passed is not RegExp, it will be cast to RegExp.
- Symbol.match as a property represents a regular expression method that uses regular expressions to match strings. Used by the string.prototype.match () method
- String.match (exp), if the argument (exp) passed is not a RegExp type, it is converted to a RegExp type, as in: ’11’.macth( {num:11} ) ==> ’11’.macth(new RegExp( {num:11} ))
- String.match (exp). If you don’t want the argument (exp) to be forcibly converted to RegExp, you can implement the symbol.match method on the exp passed in
// 1. string.match(RegExp)
console.log('hello'.match(/llo/)); // ["llo", index: 2, input: "hello", groups: undefined]
// 2. String. Match (non-regexp type)
var obj = {};
var result = 'hello'.match(obj);// this equals 'hello'. Match (new RegExp(obj))
console.log(result); // ["e", index: 1, input: "hello", groups: undefined]
// 3. Customize the matching rule of string.match
var obj = {
[Symbol.match]: (target) = > { / / target is foobar
let index = target.indexOf('oo');
return {
value: target.slice(index,3), index }; }};console.log('foobar'.match(obj)); // {value: "oo", index: 1}
Copy the code
- Symbol.replace represents, as a property, a regular expression method that replaces matched substrings in a string of characters. Used by the string.prototype.replace () method
- String.replace (exp, STR), if the argument (exp) passed in is of non-regexp type, it is converted to RegExp
- String.replace (exp, STR). If you don’t want the argument (exp) to be forcibly converted to RegExp, you can implement the symbol.replace method on the exp passed in
// 1. Symbol.replace(exp, str)
var target = 'hello';
var newStr = target.replace(/o/.'66');
console.log(newStr); // hell66
// 2. Symbol.replace(non-regexp type, STR)
var target = 'hello';
var newStr = target.replace(['o'].'77'); // Equivalent to target.replace(new RegExp(['o']),'77')
console.log(newStr); // hell77
// 3. Implement custom Symbol. Replace rule
var target = 'hello';
var obj = {
[Symbol.replace]: function(target){
var index = target.indexOf('e');
return 'haha'+ target.slice(index); }};var newStr = target.replace(obj,'66');
console.log(newStr); // hahaello
Copy the code
- Symbol.search as an attribute represents a regular expression method that returns an index in a string that matches a regular expression. Used by the string.prototype.search () method
- String.search (exp). If the argument (exp) passed in is of non-regexp type, it is converted to RegExp
- String.search (exp). If you don’t want the argument (exp) to be forcibly converted to RegExp, you can implement symbol.search on the exp passed in
// 1. string.search(exp)
var target = 'hello';
var index = target.search('ll');
console.log(index); / / 2
// 2. String. Search (non-regexp type)
var target = 'hello';
var obj = {};
var index = target.search(obj); // target.search(new RegExp(obj))
console.log(index); / / 1
// 3. Implement a custom string.search search rule
var target = 'hello';
var obj = {
[Symbol.search]: function(target){
var index = target.indexOf('ll');
returnindex; }};var index = target.search(obj);
console.log(index); / / 2
Copy the code
- Symblo.split represents, as a property, a regular expression method that splits a string at the index position that matches the regular expression. Used by the string.prototype.split () method.
- String.split (exp), if the argument (exp) passed is non-regexp, it is converted to RegExp
- String.split (exp). If you don’t want the argument (exp) to be forcibly converted to RegExp, you can implement the symbol.split method on the exp passed in
// 1. string.split(RegExp)
var target = 'hello-world';
var arr = target.split(The '-');
console.log(arr); // ["hello", "world"]
// 2. String.split (non-regexp type)
var target = 'hello-world';
var arr = target.split([The '-']);Split (new RegExp(['-']))
console.log(arr); // ["hello", "world"]
// 3. Implement a custom string. Split rule
var target = 'hello-world';
var obj = {
[Symbol.split]: function(target){
var length = target.length;
var arr = [];
for(var index = 0; index < length; index++){
arr[index] = target[index];
}
returnarr; }};var arr = target.split(obj);
console.log(arr); // ["h", "e", "l", "l", "o", "-", "w", "o", "r", "l", "d"]
Copy the code
5. Symbol associated with the complex type. [toPrimitive | toStringTag | unscopables]
- Symbol.toprimitive represents a method that converts an object to the corresponding original value. Used by the ToPrimitive abstract operation
// 1. Change the complex type to basic type
var obj = {};
// 1.1 obj to string
console.log(obj + ' & hello'); // [object Object] & hello
// 1.2 obj to number
console.log(obj - 1); // NaN
// obj to Boolean
console.log(!! obj);// true
// 2. Implement custom conversion rules
var obj = {
[Symbol.toPrimitive]: function (type) {
switch (type) {
case 'string':
return '666';
case 'number':
return 889;
case 'default':
default:
return 0; }}};// 2.1 obj to string
console.log(String(obj)); // 666 & hello
// 2.2 obj to number
console.log(obj - 1); / / 888
// 2.3 obj to Boolean
console.log(Boolean(obj)); // true
Copy the code
- Symbol.tostringtag represents a string that is used to create the default string description of the object. By the method of built-in Object. The prototype. The toString () is used
/ / 1. Object. The prototype. The toString () is used to return data type
var arr = [1],
obj = { name: 'zs' },
func = function getName() {
console.log(obj.name);
};
/ / 1.1 call Object. The prototype. The toString ()
console.log(obj.toString()); // [object Object]
/ / 1.2 this two calls are not the Object. The prototype. The toString method
/ / 1.2.1 Array. The prototype. The toString ()
console.log(arr.toString()); / / 1
/ / 1.2.2 Function. The prototype. The toString ()
console.log(func.toString()); // function getName() { console.log(obj.name); }
// 3. Change the Object type with symbol.tostringTag
obj[Symbol.toStringTag] = 'Array';
console.log(obj.toString()); // [object Array]
// Typeof return types are not affected
console.log(typeof obj); // object
Copy the code
- Symbol.unscopables represents an object whose properties, both inherited and owned, are excluded from the with environment binding of the associated object
- The use of with is not recommended, and therefore Symbol. Unscopables are also not recommended
// 1
let o = { foo: 'bar' };
with (o) {
console.log(foo); // bar
}
// 2. The Settings are not visible
o[Symbol.unscopables] = {
foo: true
};
with (o) {
console.log(foo); // ReferenceError
}
Copy the code