This is the 22nd day of my participation in Gwen Challenge

JavaScript is a dynamically typed language, also known as a weakly typed language, meaning that its variables have no type constraints and can be assigned values of any type. When operating on different types of values, conversion operations (that is, converting a value of one type to another) are involved, such as converting the string ‘123’ to the number 123.

When we know exactly what type we want to cast, we can explicitly cast the data. This type casting behavior is called “casting”.

When the type is not clear, different types of values may be evaluated. Because operators have requirements for data types, JavaScript automatically performs type conversion according to certain rules when the type does not meet the requirements. This behavior is called “implicit type conversion”.

Cast casting

The cast usually uses the Number(), String(), and Boolean() functions to manually convert values of various types to numbers, strings, or Booleans, respectively.

Conversion to numeric type

The Number function returns +0 if no argument is passed, or ToNumber(value) if any argument is passed. This ToNumber is a method on the underlying specification implementation that is not directly exposed.

According to specification 9.3, ToNumber’s result table is as follows:

The parameter types The results of
Undefined NaN
Null + 0
Boolean If the argument is true, return 1. Argument false, return +0
Number Returns the value equal to it
String If it can be parsed to a value, convert it to the corresponding value; otherwise, return NaN, as shown in the example
Object 1. primValue = ToPrimitive(input, Number)

2. ReturnToNumber(primValue).

A simple example is as follows:

// String: If it can be parsed to a numeric value, it is converted to the corresponding numeric value
Number('324') / / 324
Number('-Infinity') //-Infinity
Number('00000123') / / 123

// String: If it cannot be parsed as a number, return NaN
Number(' 324abc ') // NaN
// parseInt is less strict and takes a prefix number
parseInt(' 324abc ') / / 324
// Both ignore prefix and postfix whitespace
parseInt('\t\v\r324abc\n') / / 324
Number('\t\v\r324\n') / / 324

// The empty string is converted to 0
Number(' ') / / 0

// Boolean values: true to 1, false to 0
Number(true) / / 1
Number(false) / / 0

// undefined: becomes NaN
Number(undefined) // NaN

// null: converts to 0
Number(null) / / 0
Copy the code

ToPromitive method

As you can see from the result table, the toPrimitive method is called first if the object type is converted with Number. This method essentially takes a value and then returns a value of the primitive type. Refer to spec 9.1, Spec 8.12.8 for the syntax as follows:

ToPrimitive(input[, PreferredType])
Copy the code

Input If it is a basic type (Undefined, Null, Boolean, Number, String), the value is returned. Otherwise, the value is converted.

PreferredType Select Number or String, default to String if input is a date type, and default to Number otherwise.

If ToPrimitive(obj, Number) is used, the procedure is as follows:

  1. ifobjIs the basic type and returns directly;
  2. Otherwise, callvalueOfMethod, if it returns a raw value, returns it;
  3. Otherwise, calltoStringMethod, if it returns a raw value, returns it;
  4. Otherwise, a type error exception is thrown.

If it is ToPrimitive(obj, String), the processing is as follows:

  1. ifobjIs the basic type and returns directly;
  2. Otherwise, calltoStringMethod, if it returns a raw value, returns it;
  3. Otherwise, callvalueOfMethod, if it returns a raw value, returns it;
  4. Otherwise, a type error exception is thrown.

By default, the valueOf method of an object returns the object itself, so toString is always called. ToString returns the type string of the object (such as [Object Object]), and toString returns the concatenation of the items in an array. The date type returns the corresponding date string.

Number({}) // NaN
Number([5]) / / 5
Copy the code

You can override valueOf and toString to control the cast valueOf the object, as follows:

let obj = {
  valueOf: function () {
    return 1;
  },
  toString: function () {
    return 2; }};Number(obj) / / 1
Copy the code

Go to string

Use the String method to convert a type to a String. Refer to specification 9.8. If String takes no arguments, it returns an empty String.

The parameter types The results of
Undefined “undefined”
Null “null”
Boolean Return “true” if the argument is true. Parameter false, return “false”
Number To the corresponding string
String Returns the value equal to it
Object 1. primValue = ToPrimitive(input, String)

2. ReturnToString(primValue)

A simple example is as follows:

String(a)// An empty string

String(undefined) // undefined
String(null) // null

String(false) // false
String(true) // true

String(0) / / 0
String(-0) / / 0
String(NaN) // NaN
String(Infinity) // Infinity
String(-Infinity) // -Infinity
Copy the code

Object type toString type, also through ToPrimitive function for a layer of conversion, the specific conversion rules see above, call the toString of the object first, then use the valueOf the object.

Similarly, you can override valueOf and toString to control the cast valueOf an object, as follows:

let obj = {
  valueOf: function () {
    return 1;
  },
  toString: function () {
    return 2; }};String(obj) / / "2"
Copy the code

Convert to Boolean type

Use Boolean functions to convert a type to a Boolean type. Refer to specification 9.2. Only six values can be converted to false; the rest are converted to true.

Boolean(a)// false
Boolean(false) // false
Boolean([])

// Only the following six values can be converted to false
Boolean(undefined) // false
Boolean(null) // false
Boolean(+0) // false
Boolean(-0) // false
Boolean(NaN) // false
Boolean("") // false
Copy the code

All objects (including arrays and functions) are converted to true. The same is true for wrapping objects.

console.log(Boolean(new Boolean(false))) // true
Copy the code

Implicit type conversion

JavaScript does implicit type conversions when it encounters three situations.

  • The interoperation of different types of data, e.g1 + '1'
  • Find a Boolean value for data of a non-Boolean type, e.gif('123'){... }
  • Values of non-numeric types use the unary operator+and-)

In general, the operation will automatically call the corresponding type conversion function for the type of the expected value.

'a' ? true : false;   // Use Boolean() to convert 'a'
'5' - '2'; // Convert with Number()
+'123';  // Convert with Number()

Copy the code

There are two other special operations that need to be analyzed separately, the binary operators + and non-strict equality ==, whose implicit conversion rules are more complex.

Binary operator+

Referring to specification 11.6.1 and this article, the implicit conversion rules for the binary operator + are as follows:

When value1 + value2 is calculated:

  1. lprim = ToPrimitive(value1)
  2. rprim = ToPrimitive(value2)
  3. iflprimIs a string orrprimIs a string, then returnToString(lprim) andToString(rprim)Splicing results of
  4. returnToNumber(lprim)ToNumber(rprim)The operation result of

A few examples are as follows:

let obj1 = {
    valueOf() {
        return 1;
    },
    toString() {
        return '2'; }}let obj2 = {
    valueOf() {
        return 1;
    },
    toString() {
        return '2';
    }
}
obj1 + obj2 === 2 // true

null + 1= = =1 // true[] + [] = = ="" // true
console.log({} + []); // "[object Object]"
console.log({} + {}); // "[object Object][object Object]"
Copy the code

= =Nonstrict equality

Refer to specification 11.9.3, non-strict equality comparison rules are shown in the following table:

The compared value B
Undefined Null Number String Boolean Object
The value being compared is A Undefined true true false false false false
Null true true false false false false
Number false false A === B A === ToNumber(B) A=== ToNumber(B) A== ToPrimitive(B)
String false false ToNumber(A) === B A === B ToNumber(A) === ToNumber(B) A== ToPrimitive(B)
Boolean false false ToNumber(A) === B ToNumber(A) === ToNumber(B) A === B ToNumber(A) == ToPrimitive(B)
Object false false ToPrimitive(A) == B ToPrimitive(A) == B ToPrimitive(A) == ToNumber(B)

A === B

A few key points to remember:

  • Undefined and Null return true to themselves or each other, false to others;

  • NaN == with any data, including NaN, is false;

  • Boolean types are implicitly converted to Number for comparison when performing == operations on other types.

  • String is converted to Number for comparison with Number and Boolean.

  • Objects are compared to other types after ToPrimitive conversion.

false= =undefined // false
false= = []// true[] = =! []// true

// all of the following are true
false= ="0"[] = =0
""= = [null]
0= ="\n"[] = =0
+0= = -0
0= =!!!!!null; 
0= =!!!!!undefined;

// String correlation comparison, which is used to compare reference values of objects
const string1 = "hello";
const string2 = String("hello");
const string3 = new String("hello");
const string4 = new String("hello");

console.log(string1 == string2); // true
console.log(string1 == string3); // true
console.log(string2 == string3); // true
console.log(string3 == string4); // false

// Because booleans are converted to numbers for comparison
// If conditions are not recommended
if (a == true) {}
/ / advice
if (a) {}
/ / or
if(!!!!! a) {}Copy the code

Because implicit conversion is automatic, it is not easy to detect, and exceptions are easy to occur. Therefore, you are advised to perform explicit type conversion in scenarios where explicit types are used.

By the way, strict equality === is different from object.is,

  • +0 === -0 // true.Object.is(+0, -0) // false
  • NaN === NaN // false.Object.is(NaN, NaN) // true

The relevant data

Conversion of data types

JavaScript deep headache type conversion

Equality judgment in JavaScript