JavaScript 数据类型与检测方法

JavaScript 基本类型、引用类型及四种类型检测方式

问题

JavaScript 有哪些数据类型?如何检测数据类型?

解答

数据类型

基本类型(7 种)undefinednullbooleannumberstringsymbolbigint

引用类型Object(包括 Array、Function、Date、RegExp、Error 等)

检测方法

1. typeof

// 基本类型
typeof undefined    // "undefined"
typeof true         // "boolean"
typeof 123          // "number"
typeof "abc"        // "string"
typeof Symbol()     // "symbol"
typeof 123n         // "bigint"

// 特殊情况
typeof null         // "object" (历史遗留 bug)
typeof function(){} // "function"
typeof []           // "object"
typeof {}           // "object"

2. instanceof

// 检测引用类型,基于原型链
[] instanceof Array     // true
[] instanceof Object    // true
({}) instanceof Object  // true

// 无法检测基本类型
"abc" instanceof String // false
123 instanceof Number   // false

// 手动实现 instanceof
function myInstanceof(obj, constructor) {
  let proto = Object.getPrototypeOf(obj);
  while (proto !== null) {
    if (proto === constructor.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
  return false;
}

3. constructor

// 通过构造函数判断
(123).constructor === Number    // true
"abc".constructor === String    // true
[].constructor === Array        // true

// 缺点:constructor 可被修改
function Person() {}
const p = new Person();
p.constructor = Array;
p.constructor === Array  // true (已被篡改)

// null 和 undefined 没有 constructor
// null.constructor  // TypeError

4. Object.prototype.toString.call

// 最准确的检测方法
Object.prototype.toString.call(undefined)   // "[object Undefined]"
Object.prototype.toString.call(null)        // "[object Null]"
Object.prototype.toString.call(true)        // "[object Boolean]"
Object.prototype.toString.call(123)         // "[object Number]"
Object.prototype.toString.call("abc")       // "[object String]"
Object.prototype.toString.call(Symbol())    // "[object Symbol]"
Object.prototype.toString.call(123n)        // "[object BigInt]"
Object.prototype.toString.call([])          // "[object Array]"
Object.prototype.toString.call({})          // "[object Object]"
Object.prototype.toString.call(function(){})// "[object Function]"
Object.prototype.toString.call(new Date())  // "[object Date]"
Object.prototype.toString.call(/abc/)       // "[object RegExp]"

// 封装通用检测函数
function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

getType(null)       // "null"
getType([])         // "array"
getType(new Date()) // "date"

方法对比

方法优点缺点
typeof简单快速null 返回 “object”,无法区分引用类型
instanceof能检测具体引用类型不能检测基本类型,跨 iframe 失效
constructor能检测基本类型和引用类型可被修改,null/undefined 报错
toString最准确,能检测所有类型写法较长

关键点

  • 基本类型 7 种,引用类型本质都是 Object
  • typeof null === "object" 是历史 bug
  • instanceof 基于原型链,只能检测引用类型
  • Object.prototype.toString.call 是最可靠的检测方式
  • 实际开发中常封装 getType 工具函数