preface

Recently I looked back at the js foundation, just do not understand some of the judgment of data type, or do not understand typeof and instanceof principle, so I plan to study 🤭

You can check out this article on prototypes at 🤭

A Brief Introduction to JavaScript Prototypes

The data type

The latest ECMAScript standard defines eight data types:

  • Seven kinds of

    Original type:

    • Boolean
    • Null
    • Undefined
    • Number
    • BigInt
    • String
    • Symbol
  • And the Object

If you are unfamiliar with BigInt’s original datatype, it solves some of the problems, such as integers greater than 253-1. This was originally the largest Number that could be represented as Number in Javascript. BigInt can represent an arbitrarily large integer.

Now that we know about data types, let’s look at how to detect them.


Detection data type

typeof

The typeof operator returns a string representing the typeof the unevaluated operand.

To summarize the possible return values:

  • “undefined”
  • “object”
  • “boolean”
  • “number”
  • “bigint”
  • “string”
  • “symbol”
  • “function”

Additional Information:

typeof null === 'object';
Copy the code

This is probably a JavaScript design Bug. The MDN specification explains it this way:

In the original implementation of JavaScript, values in JavaScript were represented by a tag representing a type and actual data values. The type label of the object is 0. Because null represents a null pointer (with a value of 0x00 on most platforms), null has a type label of 0 and typeof NULL therefore returns “object”.

Typeof does not tell you exactly what typeof object it is, and does not tell you exactly what typeof object it is when determining null. To determine what kind of object it is, we need to use the instanceof operator, as we will see later.

With typeof in mind, we should consider how JavaScript stores data, or what is the data type tradeoff for a variable?

In the initial version of javascript, the 32-bit system was used to store the type information of variables in the low order for performance:

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

But, for undefined and NULL, the information storage for these two values is a bit special.

Null: The null pointer corresponding to the machine code, usually all zeros.

Undefined: an integer of −2^30!

As a result, Typeof has a problem judging null, because null is treated as an object because all machine code is zero.

So, a bit of a ◡ item (●’◡’●)


instanceof

The instanceof operator is used to check whether the constructor’s prototype property appears on the prototype chain of an instance object.

grammar

An instance object Construtor a constructor objectCopy the code
// Define the constructor
function C(){} 
function D(){} 

var o = new C();


o instanceof C; // true because object.getProtoTypeof (o) === c.protoType


o instanceof D; // false, because d.prototype is not on o's prototype chain

o instanceof Object; / / true, because the Object. The prototype. IsPrototypeOf (o) returns true
C.prototype instanceof Object // true

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false, c. protoType refers to an empty object that is not on o's prototype chain.

D.prototype = new C(); / / inheritance
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true because c. prototype is now on the prototype chain for O3
Copy the code

It is important to note that if the expression obj instanceof Foo returns true, it does not mean that the expression will always return true, because the Foo. Prototype property may change and the value may not be in obj’s prototype chain. The value of the original expression will then become false. In another case, the value of the original expression can also change, which is the case of changing the prototype chain of the object obj. Although in the current ES specification, we can only read the object’s prototype and not change it, this can be done with the help of the non-standard __proto__ pseudo-attribute. For example, obj.__proto__ = {}, obj instanceof Foo will return false.

The principle of the author

To understand the Instanceof principle, we need to understand two aspects:

  • How are operators defined in the language specification
  • JavaScript prototype inheritance mechanism

Here, I translate the specification definition directly into JavaScript code as follows:

function my_instance_of(leftVaule, rightVaule) {
    if(typeofleftVaule ! = ='object' || leftVaule === null) return false;
    let rightProto = rightVaule.prototype,
        leftProto = leftVaule.__proto__;
    while (true) {
        if (leftProto === null) {
            return false;
        }
        if (leftProto === rightProto) {
            return true;
        }
        leftProto = leftProto.__proto__
    }
}
Copy the code

As you can see from the above code, the main principle of Instanceof is:

Returns true as long as the right prototype is reachable on the left prototype chain. Thus,instanceof iterates through the left variable’s prototype chain until it finds the right variable’s prototype, and returns false if the search fails, telling us that the left variable is not an instanceof the right variable.

Let’s take a look at some interesting examples:

function Foo() {}
        console.log(Object instanceof Object)
        console.log(Function instanceof Function)
        console.log(Function instanceof Object)
        console.log(Foo instanceof Object)
        console.log(Foo instanceof Function)
        console.log(Foo instanceof Foo)
Copy the code

Prototype inheritance in JavaScript

As for the principle of prototype inheritance, I will simply use a diagram to show it

This diagram is very important. For those who don’t understand the prototype chain, check out this article:

A Brief Introduction to JavaScript Prototypes

Let’s take an interesting instanceof example

Object instanceof Object

The prototype attribute of Object is object. prototype. Object is a Function created by Function. Prototype and Function. Prototype's __proto__ attribute is Object.prototype. Object instanceof Objecttrue. Let me just write it in codeCopy the code
leftValue = Object.__proto__ = Function.prototype; rightValue = Object.prototype; // Check leftValue! Prototype = Function. Prototype.__proto__ = object. prototype // Second judgment leftValue === rightValue // returntrue
Copy the code

The rest of the Function instanceof Object and other interesting examples can be implemented manually 🤭


Object.prototype.toString

Description in the ES5 specification

Can know that the Object. The prototype. ToString will eventually returns to form such as of the string of Object, class, class is refers to the detected data types, this is the key to our judgment data type.

var toString=Object.prototype.toString;

console.log(toString.call(und));  // [object Undefined]
console.log(toString.call(nul));  // [object Null]
console.log(toString.call(boo));  // [object Boolean]
console.log(toString.call(num));  // [object Number]
console.log(toString.call(str));  // [object String]
console.log(toString.call(obj));  // [object Object]
console.log(toString.call(arr));  // [object Array]
console.log(toString.call(fun));  // [object Function]
console.log(toString.call(date));  // [object Date]
console.log(toString.call(reg));  // [object RegExp]
console.log(toString.call(err));  // [object Error]
console.log(toString.call(arg));  // [object Arguments]
Copy the code

The ultimate method of data type detection

/** * @desc Data type detection * @param obj Data to be detected * @return {String} type String */
 let type = (obj) = > typeofobj ! = ='object' ? typeof obj : Object.prototype.toString.call(obj).slice(8.- 1).toLowerCase();

Copy the code

Separate detection of data types

/** * @desc Undefined type detection * @param obj Data to be detected * @return {Boolean} Boolean value */
let isUndefined = obj= > obj === void 0
/** * @desc Whether Null type detection * @param obj Data to be detected * @return {Boolean} Boolean value */
let isNull = obj= > obj === Null
/** * @desc Whether Boolean type detection * @param obj Data to be detected * @return {Boolean} Boolean value */
let isBoolean = obj= > typeof(obj) === 'boolean'
/** * @desc Indicates whether the Number type is detected. * @param obj Indicates the data to be detected. * @return {Boolean} Indicates a Boolean value
let isNumber = obj= > typeof(obj) === 'number'
/** * @desc Indicates whether the String type is detected. * @param obj Indicates the data to be detected. * @return {Boolean} Indicates a Boolean value
let isString = obj= > typeof(obj) === 'string'
/** * @desc Indicates whether the Object type is detected. * @param obj Indicates the data to be detected. * @return {Boolean} Indicates a Boolean value
let isObject = obj= > Object.prototype.toString.call(obj) === '[object Object]'
/** * @desc Whether to check the Array type * @param obj Data to be checked * @return {Boolean} Boolean value */
let isArray = obj= > Object.prototype.toString.call(obj) === '[object Array]'
/** * @desc Whether Function type check * @param obj Data to check * @return {Boolean} Boolean value */
let isFunction = obj= > typeof obj === 'function'
/** * @desc Indicates whether the Date type is detected. * @param obj Indicates the data to be detected. * @return {Boolean} Indicates a Boolean value
let isDate = obj= > Object.prototype.toString.call(obj) === '[object Date]'
/** * @desc Indicates whether RegExp is detected * @param obj Indicates the data to be detected * @return {Boolean} Indicates a Boolean value */
let isRegExp = obj= > Object.prototype.toString.call(obj) === '[object RegExp]'
/** * @desc Indicates whether an Error type is detected. * @param obj Indicates the data to be detected. * @return {Boolean} Indicates a Boolean value
let isError = obj= > Object.prototype.toString.call(obj) === '[object Error]'
/** * @desc Whether Arguments type check * @param obj Data to check * @return {Boolean} Boolean value */
let isArguments = obj= > Object.prototype.toString.call(obj) === '[object Arguments]'

Copy the code

conclusion

  • Using TypeOF to determine basic data types is OK. Note the problem with typeOF determining null types
  • To judge an object specifically consider instanceof, but when Instanceof judges an array, it can be judged as Obeject by Instanceof
  • More accurately judge the type of Object instance, adopt Object. The prototype. ToString. Call () method

reference

How does the V8 engine know the JS data type?

How does typeof work?

Typeof in JavaScript

JavaScript data type detection is the ultimate solution