Four methods for judging JS data types

Posted by regiemon on Sat, 22 Jan 2022 05:52:46 +0100

1,typeof
typeof is an operator, followed by a unary expression on the right, and returns the data type of the expression. The returned results are expressed in this type of string (all lowercase letters), including the following 7 types: number, boolean, symbol, string, object, undefined, function, etc.

typeof''; // string valid
typeof1; // number is valid
typeofSymbol(); // symbol valid
typeoftrue; //boolean valid
typeofundefined; //undefined valid
typeofnull; //Invalid object
typeof[] ; //Invalid object
typeofnewFunction(); // function valid
typeofnewDate(); //Invalid object
typeofnewRegExp(); //Invalid object

Sometimes the typeof operator returns confusing but technically correct values:

For basic types, you can return correct results except null.
For reference types, except function, object type is returned.
For null, the object type is returned.
For function, return the function type.
Among them, Null has its own data type Null, and the array, date and regular in the reference type also have their own specific types. For the processing of these types, typeof only returns the Object type at the top of its prototype chain. There is no error, but it is not the result we want.

2,instanceof
Instanceof is used to judge whether A is an instance of B. the expression is: A instanceof B. If A is an instance of B, it returns true, otherwise it returns false. Special attention should be paid here: instanceof detects the prototype. We use A piece of pseudo code to simulate its internal execution process:

instanceof (A,B) = {
    varL = A.__proto__;
    varR = B.prototype;
    if(L === R) {
        // Internal properties of A__ proto__  Prototype object pointing to B
        returntrue;
    }
    returnfalse;
}

As can be seen from the above process, when the proto of A points to the prototype of B, it is considered that A is an instance of B. let's look at several examples:

[] instanceof Array; // true
{} instanceof Object;// true
newDate() instanceof Date;// true
 
function Person(){};
newPerson() instanceof Person;
 
[] instanceof Object; // true
newDate() instanceof Object;// true
newPerson instanceof Object;// true

We found that although instanceof can judge that [] is an instance of Array, it thinks that [] is also an instance of Object. Why?

Let's analyze the relationship among [], Array and Object:

From instanceof, it can be judged that [] proto points to Array Prototype, while Array prototype. proto points to Object Prototype, final Object prototype. proto points to null, marking the end of the prototype chain. Therefore, [], Array and Object form a prototype chain internally:

It can be seen from the prototype chain that the proto of [] points directly to array Prototype, indirectly pointing to Object Prototype, so according to the judgment rule of instanceof, [] is an instance of Object. By analogy, similar new Date() and new Person() will also form a corresponding prototype chain. Therefore, instanceof can only be used to judge whether two objects belong to the instance relationship, but not the specific type of an Object instance.

The problem with the instanceof operator is that it assumes only one global execution environment. If a web page contains multiple frames, there are actually more than two different global execution environments, resulting in more than two different versions of constructors. If you pass in an array from one frame to another, the passed in array has different constructors from the array natively created in the second frame.

variframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
vararr = newxArray(1,2,3); // [1,2,3]
arr instanceof Array; // false

To solve the problem of Array, ES5 provides Array Isarray() method. This method is used to confirm whether an object itself is of Array type, regardless of the environment in which the object is created.

if(Array.isArray(value)){
   //Perform some operations on the array
}

Array.isArray() essentially detects the [[Class]] value of the object. [[Class]] is an internal attribute of the object, which contains the type information of the object. Its format is [object Xxx]. Xxx is the corresponding specific type. For arrays, the value of [[Class]] is [object Array].

3,constructor
When a function f is defined, the JS engine will add a prototype for F, and then add a constructor attribute on the prototype and make it point to the reference of F. As follows:

When var f = new F() is executed, f is regarded as a constructor, and F is the instance object of F. at this time, the constructor on the f prototype is passed to F, so f.constructor == F

It can be seen that F uses the constructor on the prototype object to reference itself. When F is used as a constructor to create an object, the constructor on the prototype is inherited to the newly created object. From the perspective of prototype chain, constructor F is the type of new object. The meaning of this is to make new objects have traceable data types after they are born.

Similarly, built-in objects in JavaScript do the same when built internally:

Details:

  1. null and undefined are invalid objects, so there will be no constructor. These two types of data need to be judged in other ways.

  2. The constructor of the function is unstable, which is mainly reflected in the user-defined Object. When the developer rewrites the prototype, the original constructor reference will be lost, and the constructor will default to Object

Why did it become Object?

Because the prototype is reassigned with a {}, and {} is the literal of new Object(), new Object() will pass the constructor on the Object prototype to {}, that is, the Object itself.

Therefore, in order to standardize the development, when rewriting the object prototype, it is generally necessary to re assign a value to the constructor to ensure that the type of the object instance is not tampered with.

4,toString
toString() is the prototype method of the Object. Calling this method returns [[Class]] of the current Object by default. This is an internal attribute in the form of [object Xxx], where Xxx is the type of Object.

For Object objects, you can directly call toString() to return [object Object]. For other objects, you need to call call / apply to return the correct type information.

Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(newFunction()) ; // [object Function]
Object.prototype.toString.call(newDate()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(newRegExp()) ; // [object RegExp]
Object.prototype.toString.call(newError()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window is a reference to the global object global