JS has a lot of data types, the recognition of different data types and mutual conversion is also a common test point in the interview, this article is mainly about type conversion and type detection.

The data type

Data types in JS fall into two main categories: primitive types (value types) and reference types. The common data types are as follows:

The primitive data type is stored in the stack, and the reference type is stored in the stack as a reference address that points to a data object in the heap. Need to be aware of is null here we calculate in primitive types, but when you use typeof will find he is object, the reason is that even if he is an object, that he should save a reference to the address in the stack, but he is an empty object, so the address is empty, also is not corresponding to the heap of any data, there is no data on the heap, he It only exists on the stack, so it counts as primitive. The main reference types are Object, Array and Function, which are also derived from Object. A more detailed knowledge of these two types in memory can be found in this article.

Here’s a look at the differences between the two types:

The original type

  1. The value of the original type cannot be changed, and can only be reassigned. Trying to modify it as follows does not work, but the whole reassignment does.

  2. Primitive comparisons compare values, and if values are equal, they are equal

Reference types

  1. The value of the reference type can be changed. Note that although we have changed the attributes of A, the reference address of A on the stack has not changed.

  2. Reference types are compared to their index address, not their value. For example, the following two objects look the same, but their reference addresses are different.

    To make them equal, you simply assign b to a so that they have the same reference address and are equal.

Type conversion

Type conversion is performed when different types of data are evaluated, as in the following example:

In the example above, we use addition and subtraction to operate on several non-numeric types. In this case, JS performs an implicit type conversion, and then performs addition and subtraction. In addition to the implicit conversion of JS itself, sometimes we also perform active type conversion, which is considered explicit type conversion.

Implicit type conversion

Convert to string

Often occurs in + operations, and one of the operands is not of numeric type

let s = 4 + 'px' + 5;
console.log(s);   // 4px5

s = 123e-2 + 'a';  
console.log(s);   / / 1.23 a
Copy the code

To numerical

Often used in mathematical operations, except for the + operation, which represents a concatenation string

let s = 'abc';
console.log(+s, -s); // NaN, NaN

s = '123';
console.log(+s, -s); // 123 -123

s = new Date(a);console.log(+s, -s);  // 1588675647421 -1588675647421
Copy the code

Converted to bool scenario

Often used in if or logical operations

let s = 'abc';
if(s) {
  console.log(s);  // abc
}

console.log(!! s);// true
Copy the code

The following values are converted to false when bool is converted, and all other values are true:

  1. 0
  2. NaN
  3. “(empty string)
  4. null
  5. undefined

The = = operator

When we use == to compare, if the two sides have different types, JS will perform type conversion, and then compare, === will not perform type conversion, if the two sides have different data types, return false.

Just a few of these cases are listed above, but for more, you can refer to the following table, which comes from MDN. The contents of this table are quite large, some of which are directly defined by the specification, such as null == undefined, and there is not much logic to it. We can check this table if we are not sure, but in practice it is not recommended to use ==, because if you remember the conversion relationship incorrectly, you can introduce a difficult bug. It is generally recommended to use ===.

Transformation rules

Here are some conversion rules from the DEFINITIVE JS Guide:

Explicit type conversion

Explicit casting is when we write our own code to explicitly convert the type to make the code look cleaner and is recommended for actual development.

Turn the string

An explicit conversion to a String can be done using the toString method, which usually results in the same execution as the String() method. The toString method of type Number also supports arguments that specify which base to convert to. ToString (); null; undefined; toString();

ToString methods of type Number support base:

Turn the numerical

Converting to a value is easy, and it’s used a lot, with these two global methods: parseInt and parseFloat.

Object to string

Converting objects to strings and values is a little more cumbersome, so let’s explore that separately. There are three main ways to convert an object to a string:

  1. value.toString()

    We’ve seen this before

  2. “‘ + value. This is the implicit conversion mentioned earlier, but values are converted in the following order:

    1. First callvalue.valueOfMethod that returns if the value is original
    2. Otherwise the callvalue.toStringMethod that returns if the value is original
    3. Otherwise TypeError is reported
  3. String (value). This is the explicit conversion mentioned earlier. The process is similar, but toString and valueOf are called in a different order.

    1. First callvalue.toStringMethod that returns if the value is original
    2. Otherwise the callvalue.valueOfMethod that returns if the value is original
    3. Otherwise TypeError is reported

Note that the Date object is a bit special in that it always calls the toString method.

Let’s write a code to verify:

Object.prototype.valueOf = function() {
  return 'aaa';
}

Object.prototype.toString = function() {
  return 'bbb';
}

let a = {};
let b = ' ' + a;
let c = String(a);

console.log(b);
console.log(c);
Copy the code

The output from the above code is, as expected:

Object rotation value

There are two main ways to convert an object type to a value:

  1. +value
  2. Number(value)

The execution logic is the same for both:

  1. First callvalueOfMethod that returns if the value is original
  2. Otherwise, calltoStringMethod, and then thetoStringConverts the return value of the

Here’s an example as usual:

Object.prototype.valueOf = function() {
  return {};
}

Object.prototype.toString = function() {
  return 'bbb';
}

let a = {};
let b = +a;
let c = Number(a);

console.log(b);
console.log(c);
Copy the code

The output of the above code is NaN because the BBB returned by our toString method cannot be converted to a normal value.

Type test

Type detection is a problem we often encounter, and various types of detection methods are often asked in interviews. The following are several commonly used types of detection methods.

typeof

The most common type detection method is typeof:

let a;
typeof a;   // undefined

let b = true;
typeof b;   // boolean

let c = 123;
typeof c;   // number

let d = 'abc';
typeof d;   // string

let e = () = > {};
typeof e;   // function

let f = {};
typeof f;   // object

let g = Symbol(a);typeof g;   // symbol
Copy the code

instanceof

Typeof is the simplest, but it can only determine the basic type, and not the object if it is an object. Instanceof checks whether an object is an instanceof a class. This check is based on object-oriented and prototype chains. Read more about instanceof in this article. Here’s an example:

let a = new Date(a); ainstanceof Date;  // true
Copy the code

constructor

The constructor principle is similar to instanceof above, which is also based on object-oriented and prototype chains. An object whose constructor refers to an instance of a class can be inferred from its constructor. The specific principle is also explained in detail in the article mentioned above. Again, use the above example:

let a = new Date(a); a.constructor ===Date;  // true
Copy the code

When using constructor judgment, be aware that this detection may not work if the constructor on the prototype has been modified, for example:

function a() {}
a.prototype = {
  x: 1
}

let b = new a();
b.constructor === a;    // Note that this is false
Copy the code

The constructor attribute hangs below a.protoType and overwrites the entire prototype when assigning a.protoType. Constructor, which does not have the property at all. If we had to access it, we would have to go to the prototype chain and find Object:

To avoid this problem, when we add attributes to the prototype, it is best not to overwrite the whole thing, but to add only the attributes we need.

a.prototype.x = 1;
Copy the code

If you must cover the entire section, add constructor back:

a.prototype = {
  constructor: a,
  x: 1
}
Copy the code

duck-typing

Duck typing Is an animal that looks like a duck, walks like a duck, quacks like a duck, we think it’s a duck. That is, we can tell if a duck is a duck by his appearance and behavior, rather than accurately testing his genes for duck. This approach is scientifically imprecise, of course, but it works in some scenarios. In programming language, it is to see if an object has certain properties and methods to determine whether it is the object we want. For example, some open source libraries have the following notation for determining whether an object is an array:

function isArray(object) {
  returnobject ! = =null && 
    typeof object === 'object' && 
    'splice' in object && 
    'join' in object
}

isArray([]);  // true
Copy the code

This is the way to determine if a target object is an Array by checking if it contains the Array it should be. It’s called looking like a duck, it’s a duck. However, an object with splice and join methods can also pass this detection, so this is not accurate and only applies to some scenarios.

Object.prototype.toString.call

Object. The prototype. ToString. Call is more accurate, can be used to determine the native Object which is specific type:

Object.prototype.toString.call(new Array());   // [object Array]
Object.prototype.toString.call(new Date());    // [object Date]
Copy the code

This method returns [object XXX], which is the corresponding constructor name. But it can only detect native objects, not custom types:

function a() {}
let b = new a();

Object.prototype.toString.call(b);   // [object Object]
Copy the code

You can see that for instance B of custom class A, we still get [Object object] instead of [Object A] as we expected.

Some native methods: array. isArray, number. isInteger

In order to solve the problem of type detection, JS also introduces some native methods to provide support, such as array. isArray and number. isInteger. Array.isArray can be used to check whether an object is an Array:

Array.isArray([]);   // true
Array.isArray(123);  // false
Copy the code

Number. IsInteger can be used to check whether an object is an integer:

Number.isInteger(1);     // true
Number.isInteger(-1);    // true
Number.isInteger(-1.1);  // false
Number.isInteger('aaa'); // false
Copy the code

If there are native detection methods, we certainly recommend using the native method, but there are not so many and comprehensive native methods at present, and most of the time, we still need to use the previous method to detect the type.

section

JS actually does not have a perfect method to detect all types, the specific detection method needs us to choose and choose according to the actual situation. Here is a summary of several methods:

conclusion

  1. JS has two types of data, primitive and reference types, and reference types are mainly objects.
  2. When we use+, logical judgment or= =There are implicit type conversions.
  3. Sometimes implicit type conversions produce undesirable results. If we are sure we want to make a judgment or cast, it is better to use explicit, e.g= = =Rather than= =.
  4. Object conversion to strings and values may require tuningvalueOfandtoStringMethod, call order depends on the specific scenario.
  5. JS does not have a perfect type detection method, we had better choose a specific detection method according to the needs.

At the end of this article, thank you for your precious time to read this article. If this article gives you a little help or inspiration, please do not spare your thumbs up and GitHub stars. Your support is the motivation of the author’s continuous creation.

Welcome to follow my public numberThe big front end of the attackThe first time to obtain high quality original ~

“Front-end Advanced Knowledge” series:Juejin. Cn/post / 684490…

“Front-end advanced knowledge” series article source code GitHub address:Github.com/dennis-jian…