This post was first posted on my personal blog: brownhu.site

preface

Type checking was done manually before strongly typed languages (Typescript, flow.js), and in a variety of ways. This paper tries to summarize the best way to check all types, and explain the principle of all ways, if there is a mistake please you big guy correct, in addition to the type of inspection of course embrace strong type I think is the future.

Es6 after the new addition of Symbol type, so far there are a total of 7 types of JavaScript, but there are classification (set WeakSet Map WeakMap), we will explore based on these types:

  • null
  • undefined
  • boolean
  • number
  • string
  • object (set WeakSet Map WeakMap)
  • Symbol (new in ES6)

Typeof

The first is Typeof. Typeof is probably the most familiar way to determine types, but it’s not perfect, and in some cases it’s biased. Let’s take a look at a few examples:

// Determine the base type first
typeof 1 // number
typeof 'Hellow world ! ' // string
typeof true // boolean
typeof null // object
typeof undefined // undefined

let s = Symbol(a)typeof s // symbol
Copy the code

You can see that null makes an error, which you more or less know from the interview questions. Then let’s look at reference types:

const obj = Object.create(null) // It was created this way because of programming habits...
function foo() {}
const arr = []
const s = new Set(a)const ws = new WeakSet(a)const m = new Map(a)const wm = new WeakMap(a)typeof obj // object
typeof foo // function
typeof arr // object
typeof s // object
typeof ws // object
typeof m // object
typeof wm // object
Copy the code

We find that Typeof does not distinguish between reference types other than function. As to why this is the case, take a look at how typeof works.

Typeof principle

How does JS store data types?

JavaScript uses the first three digits of the data type for performance purposes when storing underlying variables. Typeof uses the first three digits to determine the type:

  • 000: object
  • 001: an integer
  • 010: a floating point number
  • 100: string
  • 110: Boolean

Two special types:

  • undefined: -2^30
  • Null: all is 0

Because null’s machine code is all zeros, its type label is naturally 000, so typeof NULL returns “object”.

instanceof

Instanceof is limited in that it requires that the target of the determination be an object, while instanceof works by returning true whenever the prototype on the right appears on the prototype chain on the left. So instanceof is more appropriate to determine whether an instance is of its parent or ancestor type.

Basic implementation of the code:

function instance_of(L, R) {    // L represents the left expression, R represents the right expression
 var O = R.prototype;           // take the display prototype of R
 L = L.__proto__;               // take the implicit prototype of L
 while (true) { 
   if (L === null) 
     return false; 
   if (O === L)                 // Return true if O is strictly L
     return true; L = L.__proto__; }}Copy the code

Let’s look at the example directly:

const obj1 = Object.create(null)
const obj2 = {}

obj1 instanceof Object // false
obj2 instanceof Object // true
Copy the code

You can see how instanceof works very clearly from this example, because obj1 is created with object.create (null) and has nothing on the prototype chain:

The _proto_ of an Object generated directly from a {} assignment refers to an Object:

So it makes a difference,

Object.prototype.toString.call()

This method can be said to be a more comprehensive type judgment method at present, or take a look at the example:

Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(123) // "[object Number]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call('Hellow world ! ') // "[object String]"
Object.prototype.toString.call({ a: 123 }) // "[object Object]"
Object.prototype.toString.call(Symbol()) // "[object Symbol]"
Object.prototype.toString.call([1.2.3]) // "[object Array]"
Object.prototype.toString.call(function a() {}) // "[object Function]"
Object.prototype.toString.call(new Date()) // "[object Date]"
Object.prototype.toString.call(Math) // "[object Math]"
Object.prototype.toString.call(new Set()) // "[object Set]"
Object.prototype.toString.call(new WeakSet()) // "[object WeakSet]"
Object.prototype.toString.call(new Map()) // "[object Map]"
Object.prototype.toString.call(new WeakMap()) // "[object WeakMap]",/'.lk
Copy the code

To say the Object. The prototype. ToString. Call () sets in the most of the type of test is not the wind, can be said to be more perfect type checking. As for the principle. You can walk to talk about the Object prototype. ToString