When it comes to JS type judgment, we first understand the data type content in JS.

JS data base type and reference type

  • Basic types: undefined, NULL, string, number, Boolean, symbol (ES6)
  • Common basic types: undefined, null, symbol (ES6)
  • Special basic packing types: String, Number, Boolean
  • Reference types: Object, Array, RegExp, Date, Function

【JS】 The difference between string and string, and the difference between primitive types and wrapper classes

Several ways to determine a type

typeof value

  • Values: ‘undefined’/’ Boolean ‘/’ string ‘/’ number ‘/’ object ‘/’ function ‘/’ symbol ‘
  • Typeof cannot determine the typeof an object, such as Array
  • Typeof NULL is ‘object’, which is actually incorrect because null is not of type object.

Judgment principle: Store the type information of a variable according to the machine code low 1-3 bits.

  • 000: object
  • 010: floating point number
  • 100: string
  • 110: Boolean
  • 1: the integer

Because null is all machine code 0, TypeOF recognizes null as the object TypeOF principle

  • Applicable scenarios: Determine basic types other than object. Avoid null.
  • Limitations: Not suitable for judging Object,function,array and other reference types

value instanceof Type == true/false

  • See if ___proto____ points to the same object as the prototype on the right
function new_instance_of(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // Take the prototype value of the right expression
    leftVaule = leftVaule.__proto__; // Take the __proto__ value of the left expression
    while (true) {
    	if (leftVaule === null) {
            return false;	
        }
        if (leftVaule === rightProto) {
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}
Copy the code

Instanceof principle

  • Limitations: Assume there is a single global environment. If the web page contains multiple frameworks, there are more than two different global execution environments because there are more than two different versions of the Array constructor. If you pass an array from one framework to another, the array passed is different from the array constructor created natively in the second framework. Javascript Advanced Tutorial

Reference types: Object. The prototype. ToString. Call (value)

  • The principle of

Object. The prototype. ToString key code, the Object returned is’ [Object ‘+ classof (this) +’] ‘string. This method returns the class string of the current this object

'use strict';
  require('./_redefine') (Object.prototype, 'toString'.function toString() {
    return '[object ' + classof(this) + '] ';
  }, true);
Copy the code

Classof (this) pseudocode logic:

this= = =undefined;return 'Undefined'
this= = =null;return 'Null'
O = ToObject(thisValue) converts the current object toObjectBecause in the jsObjectKey values can only be string orSymbolType IsArray(O) Check whether it is an array object IsArray check logic: Type(O) Check whether it is an arrayObjectNot directlyreturn false; O is forArrayExotic Object: If O's [[DefineOwnProperty]] andArrayAll key values defined by the built-in are strings that can be converted to numbers, and the final number range must be in0~2^32-1Within the power, length has to be greater than0All keys correspond to array index.... I think this is aArrayObject,return 'Array'; .Copy the code

Note: The implementation logic may be slightly different in different versions of the JS specification

ECMA#sec-object.prototype.tostring

  • Application:
Array.isArray = function(value) { 
    return Object.prototype.toString.call(value) === '[object Array]';
}

// A generic type determination method
function type(value,typeStr){
	var str =  Object.prototype.toString.call(value);
    var curType = str.slice(8,str.length-1);
    return curType.toLowerCase() === typeStr.toLowerCase(); 
}
Copy the code

The Object reference toString

The evolution of the Object. The prototype. The toString method

A recent review of the latest ECMA262 documentation found the following Note:

Historically, this function was occasionally used to access the String value of the [[Class]] internal slot that was used in previous editions of this specification as a nominal type tag for various built-in objects.

In previous versions this method read the string value of the [[Class]] built-in slot as the type name of the built-in object

The above definition of toString preserves compatibility for legacy code that uses toString as a test for those specific kinds of built-in objects. It does not provide a reliable type testing mechanism for other kinds of built-in or program defined objects. In addition, programs can use @@toStringTag in ways that will invalidate the reliability of such legacy type tests.

In the new version you can read @@toStringTag above the object to determine the type name of the built-in object

The [[Class]] built-in slot string is deprecated in subsequent updates to the built-in object. [[class]] property in ES2015

The @@toStringTag attribute is accessible via the built-in Symbol, symbol.toStringTag

Symbol.toStringTag

What if we changed Symbol. ToStringTag

var str = new String('123'); str[Symbol.toStringTag] = 'test'; console.log(Object.prototype.toString.call(str)); // Output [object test]Copy the code

So this property can be overridden

Different typesSymbol.toStringTagContent (code source lodash)
const argsTag = '[object Arguments]'
const arrayTag = '[object Array]'
const boolTag = '[object Boolean]'
const dateTag = '[object Date]'
const errorTag = '[object Error]'
const mapTag = '[object Map]'
const numberTag = '[object Number]'
const objectTag = '[object Object]'
const regexpTag = '[object RegExp]'
const setTag = '[object Set]'
const stringTag = '[object String]'
const symbolTag = '[object Symbol]'
const weakMapTag = '[object WeakMap]'

const arrayBufferTag = '[object ArrayBuffer]'
const dataViewTag = '[object DataView]'
const float32Tag = '[object Float32Array]'
const float64Tag = '[object Float64Array]'
const int8Tag = '[object Int8Array]'
const int16Tag = '[object Int16Array]'
const int32Tag = '[object Int32Array]'
const uint8Tag = '[object Uint8Array]'
const uint8ClampedTag = '[object Uint8ClampedArray]'
const uint16Tag = '[object Uint16Array]'
const uint32Tag = '[object Uint32Array]'
Copy the code

conclusion

  • Check whether the data is a basic data type: Typeof
  • Determine whether the data is what kind of reference types: Object. The prototype. ToString. Call (this)
  • Determine if the data is a subset of another type: instanceof

Other reference

Type Judgment of JavaScript Topics (Part 2)