preface

Recently, I have finished reading Symbol in the fourth edition of the Little Red Book. In fact, I have studied Symbol in the third edition of the Little Red Book and javascript authoritative guide before. Every time I read here, I refresh my cognition of this type

Official Symbol

Symbol is a primitive data type. The Symbol() function returns a value of type Symbol, which has static attributes and static methods. Its static attributes expose several built-in member objects; Its static method exposes the global Symbol registry and is similar to the built-in object class, but as a constructor it is incomplete because it does not support the syntax: “new Symbol()”. Each Symbol value returned from Symbol() is unique. A symbol value can be used as an identifier for object properties; This is the only purpose of this data type

cognitive

First of all, I think there must be a type because some problems need to be solved by this type. This is just like the appearance of Fiber architecture in React. What can Symbol do? May think of its research is not deep only can create a unique value guarantee uniqueness but this is just part of it, in fact there are many like in our work principle of some commonly used built-in are achieved by Symbol such as a judge or iteration and conversion type only if they are not in the normal development research might not understand, But don’t finish reading this article

answer

Question 1: Why can’t Symbol be instantiated as a constructor?

Sybmol is not a constructor if you instantiate Sybmol directly using the New Symbol constructor

2. Constructors like String, Object, and Boolean can be instantiated, but Symbol can’t. As we all know that Symbol is a new type in Es6 in the later period, so when adding this type, he will consider whether users often carry out instantiation operations in practical applications

3. This can be seen in the older constructors. When we use basic types, most of the time we create them as literals rather than new strings. So the official idea is that instantiation isn’t happening very often and there’s no need to expand the way you can instantiate it

let a2 = 'The wind is clear' // the literal way
let a3 = new String('The wind is clear') // constructor mode
Copy the code

4. Why is new instantiation prohibited? The main use of Instancof to judge, a simple implementation can see the code

function _Symbol() {
  if (this instanceof _Symbol) {
    throw new Error('Uncaught TypeError: _Symbol is not a constructor')}return this
}
console.log(_Symbol()) //Window
console.log(new _Symbol()) //_Symbol is not a constructor
Copy the code

5. The hidden problem is that when we declare a literal directly, if we use typeof, for example, it will return a string, but you can also call the above methods as objects. The principle behind this is that when you define a string, it will actually call the new String method to generate an instance, so when you call split, slice, etc., it will call the method in the string instance

let a4 = 'Invincible in the East' 
console.log(typeof a4) //string
Copy the code

Question 2: What problem does the appearance of Symbol solve?

First of all, the appearance of Symbol has two aspects. One is to provide a unique attribute name, which fundamentally prevents the problem of naming conflict. For example, the following is false even though it is the same

let a1 = Symbol(Linghu Chong)
let a2 = Symbol(Linghu Chong)
console.log(a1 === a1) // false
Copy the code

2. The second aspect is Symbol, which provides a lot of built-in methods. These methods are just like what I said above that many commonly used methods need to be called internally. Similarly, instanceof is also behind the call to symbol.hasinstance. In my opinion, these may be the greater use of Symbol, like creating unique variables above, which may not be used much in mainstream framework development

In field

Let’s do a few 🌰 exercises to see Symbol’s support for our common approach

Symbol.iterator

Iterator returns an iterator, and then we go through the iterator directly and it returns the value in the array. If we go through the ARR directly, we can also return the value in the array, How to prove that the principle behind it is the iterated Symbol. Iterator

let arr = [1.2.3]   
​
console.log(arr[Symbol.iterator]()) // Array Iterator {}for (let item of arr[Symbol.iterator]()){
  console.log(item) / / 1, 2, 3
}
​
for (let item of arr){
   console.log(item) / / 1, 2, 3
}
​
Copy the code
  • So let’s do an experiment with arRSymbol.iteratorSet tonull, and you can see the returnarr is not iterableIn fact, this shows that anything can be usedfor ofThe data types that are iterated are all iterated behind themSymbol.iterator
 let arr = [1.2.3]   
​
 arr[Symbol.iterator] = null // Set the iterator here to nullfor (let item of arr){
  console.log(item) //arr is not iterable
}
Copy the code
  • Now let’s test the object, and you can see it goes straight backobj is not iterableBecause the object itself doesn’t have oneSymbol.iteratorSo it’s not supportedfor oftraverse
let obj = { name: Linghu Chong.from: 'Huashan School' }
​
for (let item of obj) {
  console.log(item) //obj is not iterable
}
Copy the code
  • Look at the example belowSymbol.iteratorImplement one that can be usedThe for of traverseAnd that’s where the results come inSymbol.iteratorGiven thefor ofTraversable features
let _Iterable = {}
​
_Iterable[Symbol.iterator] = function* () {
  yield 'Better the Middle';
  yield Yue Buqun;
  yield 'Yue Lingshan';
}
​
for (let item of _Iterable) {
  console.log(item) // Ning Zhongze, Yue Buqun, Yue Lingshan
}
Copy the code

Maybe you have other questions like why is there a “for of” when we already have a “for” loop, when we’re actually iterating over new data types like maps and sets and things like that we can use “for of” but we can’t use a regular “for” loop

Symbol.toPrimitive

ToPrimitive is a built-in Symbol value that exists as an object’s function value property. This function is called when an object is converted to its original value

let obj = { a: 1 }
​
console.log(+obj) // A primitive cast directly returns NaN
Copy the code
  • In fact, we can use this property to hijack the converted type and do something else. You can see that 2 is returned, indicating that we intercepted successfully and changed the returned value
let obj = { a: 1 }
​
obj[Symbol.toPrimitive] = function (type){
  if (type === 'number') {return 2
  }
  return null
}
​
console.log(+obj) / / 2
Copy the code
  • Let me tell you something interesting, maybe in the past people have asked you how do you do thata ==1 && a == 2 && a == 3Return true, maybe you were confused but you can do it with this property
let a = { val: 1 }
​
a[Symbol.toPrimitive] = function () {
  return a.val++
}
​
console.log(a == 1 && a == 2 && a == 3) //true
Copy the code

Symbol.hasInstance

Stick with the last example, symbol.hasinstance, which is used to determine whether an object is an instance of a constructor. So you can use it to customize the behavior of the Instanceof operator on a class, as shown in the following example

class _Array {
  // Listen on the class through hasInstance
  static [Symbol.hasInstance](instance) {
    console.log(instance) // The content of the judgment
    return Array.isArray(instance); }}console.log([] instanceof _Array) // true
console.log({} instanceof _Array) // false
Copy the code

conclusion

Symbol provides a number of built-in methods that we haven’t covered but are similar, such as Symbol. AsyncIterator extends the for await method, Symbol. Split, Symbol. We can say that the built-in attribute method of Symbol is hidden in our common methods. You may not use it directly, but it is always there. Most of this information comes from MDN and Advanced Programming Edition 4