Home  >  Article  >  Web Front-end  >  Why is there Symbol type? how to use?

Why is there Symbol type? how to use?

青灯夜游
青灯夜游forward
2022-03-22 11:04:512684browse

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!

Why is there Symbol type? how to use?

#What is Symbol? Why is there such a thing?

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]

Usage

1. Basic usage

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

2. Use the global symbol registry

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

3. Use symbols as attributes

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)

4. Commonly used built-in symbols

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.

5. Symbol.asyncIterator

is actually a Generator that returns Promise, generally used with for await of

6. Symbol. hasInstance

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

Symbol.isConcatSpreadabl

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.

Symbol.isConcatSpreadable Corresponding effect

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']

8. Symbol.iterator

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

9. Symbol.match

根据 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

11. Symbol.search

这个符号作为一个属性表示“一个正则表达式方法,该方法返回字符串中 匹配正则表达式的索引。由 String.prototype.search()方法使用”

12. Symbol.species

这个符号作为一个属性表示“一个函数值,该函数作为创建派生对象的构 造函数”。

13. Symbol.split

这个符号作为一个属性表示“一个正则表达式方法,该方法在匹配正则表 达式的索引位置拆分字符串。由 String.prototype.split()方法使用”。

14. Symbol.toPrimitive

这个符号作为一个属性表示“一个方法,该方法将对象转换为相应的原始 值。由 ToPrimitive 抽象操作使用”

15. Symbol.toStringTag

这个符号作为一个属性表示“一个字符串,该字符串用于创建对象的默认 字符串描述。由内置方法 Object.prototype.toString()使用”

16. Symbol.unscopables

这个符号作为一个属性表示“一个对象,该对象所有的以及继承的属性, 都会从关联对象的 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!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete