本文是在 ConardLi的“【JS 进阶】你真的掌握变量和类型了吗 (opens new window)”文章上的总结和扩展,集中记述了js中的变量和数据类型的相关知识点及应用场景,共分为5部分。

本文为“JS专题-变量与类型”的第5篇,5)JS的类型判断方法,推荐使用 typeofObject.prototype.toString.call(),不要用instanceof

# JS的类型判断方法

推荐使用 typeofObject.prototype.toString.call(),不要用instanceof

# typeof

typeof可以用来准确判断

  • null以外的原始类型
  • 以及function这种引用类型
typeof 'ConardLi'  // string
typeof 123  // number
typeof true  // boolean
typeof Symbol()  // symbol
typeof undefined  // undefined

typeof function(){}  // function

typeof不适用于判断

  • 大部分引用类型(除了上面的function类型)
  • 原始类型 null
typeof [] // object
typeof {} // object
typeof new Date() // object
typeof /^\d*$/; // object

typeof null // object  初版Js就留下来的bug

null不是一个对象,但为什么typeof null === object?

原理是这样的,不同的对象在底层都会表示为二进制,在js中如果二进制的前三位都为0,就会被判断为object类型null的二进制全为0,自然前三位也是0,所以typeof null === objcet。

# instanceof

WARNING

首先要明确一点的是:使用instanceof来检测数据类型不是它的设计初衷,它不能检测原始数据类型,且对于引用类型的判断也不准确

它可以判断一些引用类型,原理是通过原型链:

[] instanceof Array // true
new Date() instanceof Date // true
new RegExp() instanceof RegExp // true

简单回顾下原型链的规则:

  • 1.所有引用类型都具有对象特性,即可以自由扩展属性
  • 2.所有引用类型都具有一个__proto__(隐式原型)属性,是一个普通对象
  • 3.所有的函数都具有prototype(显式原型)属性,也是一个普通对象
  • 4.所有引用类型__proto__值指向它构造函数的prototype
  • 5.当试图得到一个对象的属性时,如果变量本身没有这个属性,则会去他的__proto__中去找

[] instanceof Array是用来判断 对象[] 是否是构造函数 Array 的实例。其原理是根据 实例对象[] 的__proto__属性 与 构造函数 Array 的prototype属性 是否引用的是同一个原型对象地址来判断的。

[] instanceof Array实际上是判断Array.prototype是否在[]的原型链上,但在这条原型链上的构造函数都是实例对象的构造函数,因此通过原型来判断就会造成误差:

[] instanceof Object // true
function(){}  instanceof Object // true

顺便想一下:怎样判断一个实例对象的直接构造函数是谁呢?

只能通过原型对象的constructor属性来判断是否:o.__proto__.constructor === M

注意:o.proto.constructor与o.constructor是一样的,其实本质就是通过原型链找到constructor属性。

# toString

  • 在拆箱操作中提到了toString函数,我们可以调用它实现从引用类型的转换。
  • 每一个引用类型都有toString方法,默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象的类型。
  • 上面提到了如果此方法在自定义对象中未被覆盖,toString才会达到预想的效果,事实上,大部分引用类型比如Array、Date、RegExp都重写了toString方法
  • 我们可以直接调用Object原型上未被覆盖的toString()方法,使用call来改变this指向来达到我们想要的效果。

Object.prototype.toString.call()

Last Updated: 4/17/2020, 5:48:17 PM