In the chapter “What You Don’t Know about Types”, you learned that javascript has a built-in Symbol. ToPrimitive property that allows you to customize type conversion operations.

typeof

We use Typeof most often for type detection, and using Typeof for basic types gives us the results we want

console.log(typeof '123')               //'string'
console.log(typeof 123)                 //'number'
console.log(typeof undefined)           //'undefined'
console.log(typeof true)                //'boolean'
console.log(typeof Symbol('foo'))       //'symbol'
Copy the code

Using Typeof for complex types is not what we want.

console.log(typeof {a: 1})                  //'object'
console.log(typeof new Date())              //'object'
console.log(typeof [1.3.4])                 //'object'
console.log(typeof new String('123'))       //'object'
console.log(typeof new RegExp())            //'object'
Copy the code

Obviously, when we type new Date(), we want to get Date; When typing an Array, you want to get an Array, but when typeof is used, the result is always Object, so when typeof is used for complex types, the result is always Object.

There are two special values, and typeof checking for them is different from what you might expect

console.log(typeof null)                //'object'
console.log(typeof function fn(){})     //'function'
Copy the code

Even though null is a primitive type, typeof results in object when used for type detection. Whereas function is a complex type, typeof detection is function.

Be careful to use Typeof for type detection when you are unsure of your type.

toString

The toString method is used instead of typeof to determine exactly what type you want

let type = {}.toString
console.log(type.call('123'))                   //'[object String]'
console.log(type.call(123))                     //'[object Number]'
console.log(type.call(true))                    //'[object Boolean]'
console.log(type.call(undefined))               //'[object Undefined]'
console.log(type.call(Symbol('foo')))           //'[object Symbol]'
console.log(type.call(null))                    //'[object Null]'
console.log(type.call(function fn() {}))        //'[object Function]'
console.log(type.call({a: 11}))                 //'[object Object]'
console.log(type.call(new Date))                //'[object Date]'
console.log(type.call(new RegExp))              //'[object RegExp]'
console.log(type.call([1.2.3]))                 //'[object Array]'
Copy the code

ToString is a good way to solve the problem of type determination. From the above example, we can see that both basic and complex types can be accurately determined.

Here {}. ToString (). Call (123), equivalent to the Object. The prototype. ToString. Call (123).

Symbol.toPrimitive

We’ve seen how to do type checking. When you do type checking, you’re actually doing a conversion. So how does conversion work inside javascript?

Javascript provides toSring and valueOf conversion methods when converting an object to a primitive type.

let o = {
    valueOf: (a)= > {console.log('valueOf'); },
    toString: (a)= > {console.log('toString');}
}
String(o)       //'toString'
Number(o)       //'valueOf'
Copy the code

When an object is converted toString, the toString method is called; The valueOf method is called when an object is converted to a number.

If a toString call does not get a base type value, valueOf is called, and a valueOf call does not get a base type, and TypeError is reported

The same is true when valueOf is called.

So why is the toString method called first when converting toString and the valueOf method when converting to number?

This is because javascript has a symbol.toprimitive property built in. When an object is to be converted to a primitive type, symbol.toprimitive is called and a hint argument is passed:

  • If I want to convert tostring.hintA value ofstringIs called sequentiallytoString,valueOf.toStringMust be executed if the basic type is returnedreturn, terminates the operation, otherwise the call continuesvalueOf, if calledvalueOfIf the base type is not available, it is reportedTypeErrorError;
  • If I want to convert tonumber.hintA value ofnumberIs called sequentiallyvalueOf,toString.valueOfMust be executed if the basic type is returnedreturn, terminates the operation, otherwise the call continuestoStringMethod if calledtoStringIf the base type is not available, it is reportedTypeErrorError;
  • If you are not sure whether to convert tostringornumber.hintA value ofdefaultIs called sequentiallyvalueOf,toString.valueOfMust be executed if the basic type is returnedreturn, terminates the operation, otherwise the call continuestoStringMethod if calledtoStringIf the base type is not available, it is reportedTypeErrorError.

How to display the user specified Symbol. ToPrimitive method, which calls the user defined Symbol. ToPrimitive method directly:

let o = {
    [Symbol.toPrimitive](hint){
        console.log(`hint: ${hint}`)},valueOf: (a)= > {console.log('valueOf'); },      / / not executed
    toString: (a)= > {console.log('toString'); }/ / not executed
}
String(o)       //'hint: string'
Number(o)       //'hint: number'
o + ' '          //'hint: default'
Copy the code