This is the 25th day of my participation in the August Challenge

preface

Javascript is a dynamically typed language, a variable may go through many functions from declaration to final use, and the data type will change, so it is particularly important to judge the data type of a variable.

Does typeOF determine the type correctly?

For historical reasons, typeof NULL is equal to Object when determining the primitive type. Both objects and arrays are converted to objects. Examples are as follows:

    typeof 1 // 'number'
    typeof "1" // 'string'
    typeof null // 'object'
    typeof undefined // 'undefined'
    
    typeof [] // 'object'
    typeof {} // 'object'
    typeof function() {} // 'function'
Copy the code

So we can see that Typeof can determine basic data types, but it is difficult to determine complex data types other than functions. Then we can use the second method, which is usually used to determine complex data types, but also can be used to determine basic data types.

For object, there are three cases:

  • The value is null
  • A value of the object
  • Value is an array

For null, we can just use ===, but what about arrays and objects? No hurry, let’s go on.

Does instanceof determine the type correctly?

Instanceof is determined by the prototype chain, but for objects, Array is also converted to Object, and there is no distinction between the basic string and Boolean types. It can be used for complex data types only, because instanceof is used to check if the prototype property of the constructor (right) is present on the prototype chain of an instance object (left). Such as:

    function Func() {}
    const func = new Func()
    console.log(func instanceof Func) // true
    
    const obj = {}
    const arr = []
    obj instanceof Object // true
    arr instanceof Object // true
    arr instanceof Array // true
    
    const str = "abc"
    const str2 = new String("abc")
    str instanceof String // false
    str2 instanceof String // true
Copy the code

Using Instanceof alone doesn’t seem to work either, but we’ve already concluded with Typeof that we can’t distinguish arrays from objects, so let’s combine instanceof to write a complete judgment logic

    function myTypeof(data) {
        const type = typeof data
        if (data === null) {
            return 'null'
        }
        if(type ! = ='object') {
            return type
        }
        if (data instanceof Array) {
            return 'array'
        }
        return 'object'
    }
Copy the code

Object.prototype.toString.call()

We implemented a version of type determination with Typeof and Instanceof above, so are there other ways to make our code more concise? The answer is to use the Object. The prototype. ToString. Call ().

Each object has a toString() method, which is automatically called when an object is represented as a text value or referenced as an expected string. By default, every Object derived from Object inherits the toString() method. If this method is not overridden in a custom Object, toString() returns [Object type], where type is the Object type. So here’s an example:

    Object.prototype.toString.call(new Date()) // [object Date]
    Object.prototype.toString.call("1") // [object String]
    Object.prototype.toString.call(1) // [object Numer]
    Object.prototype.toString.call(undefined) // [object Undefined]
    Object.prototype.toString.call(null) // [object Null]
Copy the code

Therefore, based on the above knowledge points, we can encapsulate the following general type judgment methods:

    function myTypeof(data) {
        var toString = Object.prototype.toString;
        var dataType = data instanceof Element ? "element" : toString.call(data).replace(/\[object\s(.+)\]/."$1").toLowerCase()
        return dataType
    };

    myTypeof("a") // string
    myTypeof(1) // number
    myTypeof(window) // window
    myTypeof(document.querySelector("h1")) // element
Copy the code

constructor

The constructor method is similar to instanceof, but unlike Instanceof for Object detection,constructor can also handle detection of primitive data types, not just Object types.

Note:

1. Null and undefined do not constructor; (123).constructor (123).constructor (123).constructor (123).constructor (123).constructor (123).constructor (123).constructor (123

    function A() {};
    function B() {};
    A.prototype = new B();
    console.log(A.constructor === B)  // false

    var C = new A();
    console.log(C.constructor === B)  // true
    console.log(C.constructor === A)  // false 

    C.constructor = A;
    console.log(C.constructor === A);  // true
    console.log(C.constructor === B);  // false
Copy the code

Array.isArray()

Array.isarray () is used to determine whether the value passed is an Array. Returns true if the object is Array, false otherwise.

    Array.isArray([1.2.3]); // true
    Array.isArray({foo: 123}); // false
    Array.isArray("foobar"); // false
    Array.isArray(undefined); // false
Copy the code

Regular judgment

We can convert the object and array to a string so that we can do formatting and get the final type.

    function myTypeof(data) {
        const str = JSON.stringify(data)
        if ($/ / ^ {. *}.test(data)) {
            return 'object'
        }
        if ($/ / ^ \ [* \].test(data)) {
            return 'array'}}Copy the code