JavaScript类型判断的1010种方式(史上最全)

注:本文首发于个人博客,想得到更好的阅读体验,点我移步git

在最新的 ECMAScript规范 中,一共定义了 7 种数据类型,github

  • 基本类型:String、Number、Boolean、Symbol、Undefined、Null
  • 引用类型:Object

基本类型是存储在 栈(Stack) 中的简单数据段,引用类型的值是存储在 堆(Heap) 中的对象。面试

数据类型的值存储在堆中仍是栈中,取决于值的特性。基本类型占据的空间固定,存储在栈中按值访问,能够提高变量的查询速度。引用类型的值大小不固定,不适合存储在栈中,JavaScript中采起的作法是,将引用类型的值存储在堆中,同时在栈中存储值的访问地址,因此引用类型是 按地址访问 的。app

var arr = [1, 2, 3] // 引用类型的值其实就是存储在堆内存中的对象,访问方式为按地址访问,首先找到栈区中值的地址,而后沿着地址找到堆内存中对应的对象。
复制代码

对于数据类型的判断,JavaScript 也提供了不少种方法,遗憾的是,不一样的方法获得的结果良莠不齐,下面列出了我所知道的全部的类型判断方法,若是有遗漏,欢迎在评论区补充。函数

typeof

typeof 返回未经计算的操做数的类型的字符串,可能会有一些意料以外的结果:ui

typeof null  === 'object' // true, 从一开始出现 JavaScript 就是这样的
typeof NaN === 'number' // true, 尽管 NaN 是 Not-A-Number 的缩写,typeof 仍是会返回 number
typeof [] === 'object' // true, 引用类型除了 function 外,都返回 object
typeof Infinity  === 'number' // true
typeof function() {} === 'function' // true
复制代码

typeof 可以判断大多数类型,总结 typeof 的运算规则就是:spa

  • 对于基本类型,除了 null 之外均可以返回正确结果
  • 对于引用类型,除了 function 之外都返回 object
  • 对于 null,返回 object
  • 对于函数类型,返回 function

instanceof

instanceof 用来判断 A 是不是 B 的实例,因此 instanceof 能够正确地判断对象的类型,由于其内部的实现机制是经过判断对象的原型链中是否能找到类型的 prototypeprototype

[] instanceof Array // true
[].__proto__ === Array.prototype // true
复制代码

也正是由于 instanceof 的实现本质上是基于原型链的查找,因此也会出现意料以外的状况:code

[] instanceof Object // true
[].__proto__.__proto__ === Object.prototype // true
复制代码

此外,instanceof 操做符的语法是 object instanceof constructor,要求操做符的左右两侧都必须是对象,因此没法判断 null, undefined 等类型。regexp

constructor

咱们知道当建立一个函数 F 时,JavaScript 引擎会为 F 添加 prototype 属性,而后在 prototype 属性上添加一个 constructor 属性,让它指向 F 的引用:

function F() {}
F.prototype.constructor === F // true
复制代码

这是引擎默认的行为,目的是代表对象是由那个函数构造的,在 JavaScript 中,function 其实就是一个语法糖,全部的函数本质上都是一个 Function 对象。利用这一特性,咱们能够经过 constructor 来判断对象的数据类型,由于 JavaScript 为咱们提供了不少的内置对象:

[].constructor === Array // true
''.constructor === String // true
false.constructor === Boolean // true
new Number().constructor === Number // true
复制代码

可是 constructor判断类型是 “不可靠的”,由于 constructor 属性能够被修改,好比:

var a = 1
a.constructor === Number // true
a.__proto__.constructor = String
a.constructor === Number // false
a.constructor === String // true
复制代码

constructor 也不能用来判断 nullundefined,由于他们都不是对象。

Object.prototype.toString.call

Object 原型上的方法 toString 返回一个表示该对象的字符串 [object Xxx]

ECMAScript 5 和随后的 Errata 中定义,从 JavaScript 1.8.5 开始,toString() 调用 null 返回 [object Null]undefined 返回 [object Undefined]。对于 Object 对象,直接调用 toString 就能够得到类型字符串,其余类型,须要借助 Object.prototype.toString.call/apply 来返回正确的类型值。至此,toString 成为判断数据类型最完备的一种方法:

Object.prototype.toString.call('') // [object String]
Object.prototype.toString.call(/([A-Z])\w+/g) // [object RegExp]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(NaN) // [object Number]
复制代码

咱们只须要对 toString 稍加封装就能够实现 JavaScript 中全部类型的判断,举个例子:

function getType(obj) {
  const typeClass = Object.prototype.toString.call(obj)
  const classMatch = {
    '[object String]': 'string',
    '[object Number]': 'number',
    '[object Boolean]': 'boolean',
    '[object Symbol]': 'symbol',
    '[object Object]': 'object',
    '[object Array]': 'array',
    '[object Function]': 'function',
    '[object RegExp]': 'regexp',
    '[object Date]': 'date',
    '[object Error]': 'error',
    '[object Window]': 'window',
    '[object HTMLDocument]': 'document'
  }
  if (obj == null) { // 若是是 null 或 undefined ,调用 toString 后返回
    return obj + ''
  } else { // 若是是 object 和 function ,调用 Object.prototype.toString 匹配具体的类型,其他状况直接调用 typeof
    return (typeof obj === 'object' || typeof obj === 'function') ? classMatch[typeClass] : typeof obj
  }
}
复制代码

相关推荐

勘误与提问

若是有疑问或者发现错误,能够在相应的 issues 进行提问或勘误

若是喜欢或者有所启发,欢迎 star,对做者也是一种鼓励

(完)

相关文章
相关标签/搜索