The original link

preface

In ES5, there are five basic data types: undefined, NULL, Boolean, number, string. In ES6, there is a new basic data type: Symbol. Typeof is the most commonly used javascript native built-in operator for determining data types in our development, but it has limitations.

The typeof operator

Grammar:

Typeof operator followed by operand:

typeof${operand}// or
typeof(${operand})Copy the code

Example:

typeof(undefined); // undefined
typeof(null); // object
typeof(true); // boolean
typeof(1); // number
typeof(' '); // string
typeof(Symbol(1)); // symbol
typeof(function () {}); // function
typeof([]); // object
typeof({}); // object
typeof(new Date()); // object
typeof(/abc/ig);  // object
typeof(Math);  // object
typeof(new Error('error')); // object
Copy the code

There are two things to note here:

  • typeof nullWill returnobject. In the original version of JS, the 32-bit system was used to store the type information of variables in the low order for performance reasons. The beginning of 000 represents an object, while null represents all zeros. Therefore, it was wrongly identified as object, which was adopted by ECMAScript.
  • typeofYou can’t tell exactly what the object type is. For example,typeof {}.typeof new Date().typeof /abc/ig.typeof Math, both returnobjectIs it possible to tell us that this is adateObject, that’s oneregexpObjects? . And one of the things I can’t stand is,typeof []Is returnedobject. A lot of times in our business we want to be able to distinguish exactly what isarrayorobject.

In addition, instanceof can also determine the type of an object, because the internal mechanism is to determine whether the prototype of the type can be found in the prototype chain of the object. However, this does not apply to some basic data types.

1 instanceof Number; // false
var num = new Number(1);
num instanceof Number; // true
Copy the code

thinking

Given typeof and Instanceof’s limitations, is there a relatively accurate way to determine data types? The answer is yes, it is the Object. The prototype. ToString. Call (XXX) method, the result returns to format form such as: [Object Array], [Object RegExp], [Object Date], etc. We can tell exactly what type of data the expression is based on the second word in parentheses in the return result. There is a lot of information on the web about how to use this function, and it can be represented in a variety of ways:

1. Object.prototype.toString.call(xxx);
2. ({}).toString.call(xxx);
3.[].toString.call(xxx); .Copy the code

In fact, no matter how many ways to write it, it also changes. Both call the native toString method on the prototype chain to cast the data type.

practice

The scene of a

If only six basic data types were needed, and function, array, and object were all that was needed, we could do this:

var superTypeof = function (val) {
    var ans = typeof val;
    if (ans === 'object') {
        if (val === null) {
            ans = 'null';
        } else if (Array.isArray(val)) {
            ans = 'array'; }}return ans;
}
Copy the code

IsArray (val) : val instanceof Array

test

superTypeof(undefined); // undefined
superTypeof(null); // null
superTypeof(true); // boolean
superTypeof(1); // number
superTypeof(' '); // string
superTypeof(Symbol(1)); // symbol
superTypeof(function () {}); // function
superTypeof([]); // array
superTypeof({}); // object
superTypeof(new Date()); // object
superTypeof(/abc/ig); // object
superTypeof(Math); // object
superTypeof(new Error('error')); // object.Copy the code

Scenario 2

One day, we realized that the superTypeof function above could not tell us exactly whether the Object type returned was Date, RegExp, or some other more specific Object. This time, we need to use the above mentioned Object. The prototype. ToString. Call (XXX) method.

var superTypeof = function (val) {
    var ans = typeof val;
    if (ans === 'object') {
        ans = ({}).toString.call(val).slice(8.- 1).toLowerCase();
    }
    return ans;
}
Copy the code

Testing:

superTypeof(undefined); // undefined
superTypeof(null); // null
superTypeof(true); // boolean
superTypeof(1); // number
superTypeof(' '); // string
superTypeof(Symbol(1)); // symbol
superTypeof(function () {}); // function
superTypeof([]); // array
superTypeof({}); // object
superTypeof(new Date()); // date
superTypeof(/abc/ig); // regexp
superTypeof(Math); // math
superTypeof(new Error('error')); // error.Copy the code

In this way, we can accurately determine the data type in JS.

JQuery implementation

Let’s look at how jquery implements similar functionality:

var class2type = {},
    typeStr = "Boolean Number String Function Array Date RegExp Object Error Symbol";
typeStr.split("").forEach(function (item) {
    class2type[ "[object " + item+ "]" ] = item.toLowerCase();
});
var toType = function (obj) {
    if ( obj == null ) {
        return obj + "";
    }
    return typeof obj === "object" || typeof obj === "function" ?
		class2type[ toString.call( obj ) ] || "object" :
		typeof obj;
}
Copy the code

Do you think the same implementation is not even good enough for me to write elegantly? This is not what the authors of jQuery intended.

Finally, I would like to create a powerful and lean library typeof2 from Amway that has similar features.