Four basic methods of type judgment, jquery type method, empty object detection method and class array object are studied.

Posted by sunil.23413 on Sat, 24 Aug 2019 17:12:51 +0200

I. Preface

Type judgment can sometimes be a real headache, but once you're skilled in using it, you'll feel that way. At the primary level, numbers and strings are judged. Intermediate, will judge arrays and objects. Advanced, will judge the date, regularity, error type. Advanced, will judge plainObject, empty object, window object and so on.

Basic types: String, Number, Boolean, Symbol, Undefined, Null

Reference type: Object

The basic type is also called simple type. Because it occupies fixed space, it is a simple data segment. In order to improve the speed of variable query, it is stored in the stack, that is, access by value.

Reference type is also called complex type. Because its value size will change, it can not be stored in the stack, otherwise it will reduce the speed of variable query. Therefore, its value is stored in heap, and the value stored in the variable is a pointer, pointing to the memory of the storage object, that is, access by address. In addition to Object, reference types include Function, Array, RegExp, Date, and so on.

Since ECMAScript is loosely typed, there is a need for a means to detect the data type of a given variable. JavaScript also provides a variety of approaches to this problem, but unfortunately, the results of different approaches are uneven.

Typeeof

Typeeof is the most frequently used type of judgment.

typeof('saucxs')    //'string'
typeof 'saucxs'   //'string'
typeof function(){console.log('saucxs')}   //'function'
typeof ['saucxs','songEagle',1,2,'a']    //'object'
typeof {name: 'saucxs'}    //'object'
typeof 1   //'number'
typeof undefined     //'undefined'
typeof null    //'object'
typeof /^\d/   //'object'
typeof Symbol   // 'function'

In fact, typeof is an operator, similar to add, subtract, multiply and divide. That's why you can write typeof'saucxs'.

Introduction to typeof in the JavaScript Authoritative Guide: typeof is a unary operator, placed in front of a single operand, operands can be of any type. A string whose return value represents the type of the operand.

There are six basic data types in JavaScript: string, number, boolean, null, undefined, symbol, an object type: object.

The results of the corresponding typeof values are not one-to-one correspondence, respectively: string, number, boolean, object, undefined, function, object type: object.

Note: typeof can detect function types

But there are many subdivisions of internal attributes under object: Array, Function, Date, RegExp, Error, etc.

var date = new Date();
var error = new Error();
console.log(typeof date); // object
console.log(typeof error); // object

So better distinctions are needed.

3. instanceof

The prerequisite for using instanceof: object instance of constructor. Object -- The object to be detected. Constructor -- a constructor. Explains that the use of this instance of must be used to detect the type of object, not other types.

A instance of B is used to determine whether A is an instance of B. If A is an instance of B, return true, otherwise false.

Principle: instanceof is a prototype of detection.

instanceof (a,B) = {
    var l = a.__proto__;
    var R = B.prototype;
    if(l === R) {
        // The internal property of a _proto_ points to the prototype object of B
        return true;
    }
    return false;
}

Analysis: When the _proto_of a points to the prototype of B, A is an example of B.

[] instanceof Array    //true
[] instanceof Object    //true
new Array([1,43,6]) instanceof Array    // true
new Array([1,43,6]) instanceof Object   // true

{} instanceof Object   // Uncaught SyntaxError: Unexpected token instance of
({})  instanceof Object;   //true
Object.create({'name': 'saucxs'}) instanceof  Object   //true
Object.create(null) instanceof  Object    //false is a method of creating objects that are not an instance of Object

new Date() instanceof Date   //true
new Date() instanceof Object   //true

'saucxs' instanceof Object   //false
'saucxs' instanceof String  //false
new String("saucxs") instanceof Object  //true
new String("saucxs") instanceof String  //true

1 instanceof Object   //false
1 instanceof Number   //false
new Number(1) instanceof Object  //true
new Number(1) instanceof Number  //true

true instanceof Object   //false
true instanceof Boolean   //false
new Boolean(true) instanceof Object  //true
new Boolean(true) instanceof Boolean   //true

null instanceof Object    //false
undefined instanceof Object  //false
Symbol() instanceof Symbol   //false

Note: 1. The new Date object belongs to both Object and Date. They are derived from the Object class.

2. Arrays created by literal quantities or constructors belong to both Object and Array.

3. Objects created with literal quantities of objects will report errors, {} instances of Objects; objects created with constructors belong to Objects.

4. Strings, numbers and Booleans created with literal quantities are neither Object nor their respective types; only strings, numbers and Booleans created with constructors belong to both Object and their respective types.

Discover [], the constructor creates Dite, Object, String, Number, Boolean. It belongs to both itself and Object.

For example, [], Array, Object's relationship:

It can be judged from instanceof that []. proto points to Array.prototype, and Array.prototype. proto points to Object.prototype, and finally Object.prototype. points to null, marking the end of the prototype chain. Therefore, [], Array and Object form a prototype chain inside.

From the prototype chain, we can see that proto of [] points directly to Array.prototype and indirectly 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 form a corresponding prototype chain. Therefore, instanceof can only judge whether two objects belong to instance relationship, but can not judge which type an object instance belongs to.

Existing problems:

It assumes that there is only one global execution environment. If there are multiple frameworks in a web page, there are actually more than two different global execution environments, thus there are more than two different versions of constructors. If you pass an array from one frame to another, the incoming array has different constructors from the original array created in the second frame.

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

For array problems, ES5 provides the Array.isArray() method. This method is used to confirm whether an object itself is of Array type.

if (Array.isArray(value)){
   //Perform certain operations on arrays
}

Array.isArray() essentially detects the [[Class]] value of the object, [[Class]] is an internal property of the object, which contains the type information of the object in the form of [object Xxx], and Xxx is the corresponding specific type. For arrays, the value of [[Class]] is [object Array].

IV. constructor

Define a constructor Func(), the JS engine will add prototype prototype to Func, then add a constructor attribute to prototype, and point to a reference to Func.

Instantiate a function func, var func = new Func(). At this point, the constructor on the Func prototype is passed on to func, so func.constructor === Func.

Func uses the constructor on the prototype object to refer to itself. When Func acts as a constructor to create instantiated objects, the constructor on the prototype is inherited to the newly created objects. From the perspective of prototype chain, constructor Func is the type of func of new objects. The significance of this is that data types can be tracked after new objects are created.

Built-in objects in JavaScript do the same when built internally:

'saucxs'.constructor === String    //true
new String('saucxs').constructor === String   //true
[].constructor === Array     //true
new Array([12,56]).constructor === Array     //true

new Number(12).constructor === Number    //true
new Function(console.log('saucxs')).constructor === Function     //true
new Date().constructor === Date     //true
new Error().constructor === Error     //true

window.constructor === Window   //true
document.constructor === HTMLDocument  //true

Be careful:

(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 a function is unstable, which is mainly reflected in the custom object. When the developer rewrites prototype, the original constructor reference will be lost, and the constructor will default to Object.

Why did it become Object?

Because prototype is reassigned as a {} and {} is a literal quantity of new Object(), new Object() passes the constructor on the Object prototype to {}, that is, the Object itself.

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

V. Object.prototype.toString

toString() is the prototype method of Object, which is called and returns the current object by default [[Class]]. This is an internal property in the form of a string [object xxx], where XXX is the type of the object.

What on earth is this method? See ES5 Specification Address first: https://es5.github.io/#x15.2.4.2

When the toString method is called, this step is followed:

(1) If the value of this is undefined, it returns [object Undefined];

(2) If the value of this is null, it returns [object Null].

(3) Let O be the result of ToObject(this);

(4) Let class be the value of the internal attribute [[class]] of O;

(5) Finally, return a string composed of "[object" and "class" and "]".

One sentence is: Calling Object.prototype.toString returns a string of "[object" and "class" and "]", and class determines the internal attributes of the object.

console.log(Object.prototype.toString.call(undefined)) // '[object Undefined]'
console.log(Object.prototype.toString.call(null)) // '[object Null]'
console.log(Object.prototype.toString.call(Window))  // '[object Function]'

var date = new Date();
console.log(Object.prototype.toString.call(date)) // '[object Date]'
console.log(Object.prototype.toString.call(Symbol)) // '[object Function]'

Note: Change the direction of this by call.

So the value of this class is the key to identifying object types, so using Object.prototype.toString method to identify more types can identify at least 11 types.

var number = 1;          // [object Number]
var string = '123';      // [object String]
var boolean = true;      // [object Boolean]
var und = undefined;     // [object Undefined]
var nul = null;          // [object Null]
var obj = {a: 1}         // [object Object]
var array = [1, 2, 3];   // [object Array]
var date = new Date();   // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g;          // [object RegExp]
var func = function a(){}; // [object Function]
Math    //[object Math]
JSON  //[object JSON]

Be careful:

1. In fact, Math objects and JSON objects are not judged.

2. Math objects are not classes of objects like Date and String. There are no constructors such as Math (). Math. sin () is just functions, not methods of an object.

6. Research on jquery's type API

Using the method of Object.prototype.toString, it is easy to judge various types, referring to the source code type section of jquery:

function type(obj) {
    // Kill two birds with one stone
    if (obj == null) {
        return obj + "";
    }
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[Object.prototype.toString.call(obj)] || "object" :
        typeof obj;
}

Where the class2type section

var class2type = {};

// Generating class2type mapping
"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
})

Use:

type(1);   //'number'
type('123456');  //'string'
type(true);      //boolean
type(undefined);    //undefined
type(null);     //'null'
type({name: 'saucxs'});   //'object'
type([1,2,'saucxs',3,4]);   //'array'
type(new Date());    // 'date'
type(new Error());   //'error'
type(/^\d/);    //'regexp'
type(function(){console.log('saucxs')});   //'function'
type(Symbol);   //'function'

This is perfectly achieved, judging the type of our daily needs.

It realizes judging date, regularity, error type and so on.

If you need to judge more complex, such as: empty object, window object, class array object and so on.

Empty Object for Empty Object

jQuery provides the isEmptyObject method to determine whether it is an empty object or not.

function isEmptyObject( obj ) {
        var name;
        for ( name in obj ) {
            return false;
        }
        return true;
}

Idea: To judge an empty object is to judge whether there is an attribute value or not. Once the for loop is executed, it shows that there are attributes and attributes return false.

console.log(isEmptyObject({})); // true
console.log(isEmptyObject([])); // true
console.log(isEmptyObject(null)); // true
console.log(isEmptyObject(undefined)); // true
console.log(isEmptyObject(123)); // true
console.log(isEmptyObject('')); // true
console.log(isEmptyObject(true)); // true

This judgment is mainly used to distinguish {} from {name:'saucxs'}.

Note: (1) for in is an attribute of ES6, which traverses the properties on the prototype. (2) Using Object.keys(obj) is an attribute of ES5 and does not traverse properties on the prototype.

8. Windows Objects

Windows object is the global object of client js, and it has a window attribute pointing to itself. According to this feature, we can judge whether it is a window object or not.

function isWindow(obj){
   return obj != null && obj ===obj.window;
}

Note: A common object has a window property and points to itself. For example, this:

function isWindow( obj ) {
    return obj != null && obj === obj.window;
}
let fakeWindow = {}
fakeWindow.window = fakeWindow
isWindow(fakeWindow) // true

Is it possible to modify it this way?

function isWindow(obj) {
    return !!(window && obj === window)
}

IX. Class Array Objects

If there is no concept of class arrays, for example:

Arrays and class arrays

var arr = [,,3];

The corresponding array of classes is

var arrLike = {
     2: 3,
     length: 3
}

Look at jquery's source code

function isArrayLike(obj) {

    // obj must have length attribute
    var length = !!obj && "length" in obj && obj.length;
    var typeRes = type(obj);

    // Exclude functions and Window s objects
    if (typeRes === "function" || isWindow(obj)) {
        return false;
    }

    return typeRes === "array" || length === 0 ||
        typeof length === "number" && length > 0 && (length - 1) in obj;
}

So if isArray Like returns true, at least one of three conditions must be satisfied:

(1) Is an array

(2) Length is 0

(3) The lengths attribute is a numeric type greater than 0, and obj[length - 1] must exist

The third condition: when we skip a comma directly in an array, we don't think the element exists, and we don't need to write it in the class array object, but the last element must be written, otherwise the length of the length of the length will not be the key value of the last element plus 1. For example, arrays can be written like this

var arr = [1,,];
console.log(arr.length) // 2

Rewrite to an array of classes

var arrLike = {
    0: 1,
    length: 1
}

So the qualified class array object must have the last element!

10. Judging dom Elements

isElement determines whether or not a DOM element is present.

isElement = function(obj) {
    return !!(obj && obj.nodeType === 1);
};

XI. SUMMARY

There are four main methods to judge the type: (1) typeof; (2) instanceof; (3) constructor; (4) Object.prototype.toString().

From the basic six types of judgment, you can use typeof, if it involves the internal type of the object; you can also use instanceof to detect the prototype of the object; you can also use the constructor attribute to point to their constructor; you need to use Object.prototype.toString(), if you need to determine the empty object, you can Uses ES6 for in to judge, uses the window attribute to point to oneself to judge whether is the window object. And the judgment of the class array object, and the judgment of whether the dom element is or not.

Topics: Javascript Attribute JQuery JSON