JS数据类型判断

39 阅读3分钟

在 JavaScript 中,原始值(原始数据类型)是一种既非对象也无方法或属性的数据。有 7 种原始数据类型:

除了 Object 以外,所有的类型都定义了不可变的、在语言最底层直接表示的值。我们将这些类型的值称为原始值;

除了 null 以外,所有的原始类型都可以使用 typeof 运算符进行测试。typeof null 返回 "object",因此必须使用 === null 来测试 null。

除了 null 和 undefined 以外,所有的原始类型都有对应的对象包装类型,它们为处理原始值提供了有用的方法。例如,Number 对象提供了像 toExponential() 这样的方法。当在原始值上访问属性时,JavaScript 会自动将值包装成对应的包装对象,并访问对象上的属性。

string number bigint boolean undefined symbol null

外加一个非原始值 Object

typeof

类型结果
Undefined"undefined"
Null"object"
Boolean"boolean"
Number"number"
BigInt"bigint"
String"string"
Symbol"symbol"
Function(在 ECMA-262 中实现 [[Call]];classes也是函数)"function"
其他任何对象"object"

Object.prototype.toString(Symbol.toStringTag)

将基本的 Object.prototype.toString() 用于重写过 toStirng 的对象, 返回 "[object Type]",这里的 Type 是对象的类型。如果对象有 Symbol.toStringTag 属性,其值是一个字符串,则它的值将被用作 Type。许多内置的对象,包括 Map 和 Symbol,都有 Symbol.toStringTag。一些早于 ES6 的对象没有 Symbol.toStringTag,但仍然有一个特殊的标签。它们包括(标签与下面给出的类型名相同):

  • Array
  • Function(它的 typeof 返回 "function")
  • Error
  • Boolean
  • Number
  • String
  • Date
  • RegExp

arguments 对象返回 "[object Arguments]"。其他所有内容,包括用户自定义的类,除非有一个自定义的 Symbol.toStringTag,否则都将返回 "[object Object]"。

在 null 和 undefined 上调用 Object.prototype.toString() 分别返回 [object Null] 和 [object Undefined]。

const toString = Object.prototype.toString;

console.log(toString.call(123));          // "[object Number]"
console.log(toString.call("abc"));        // "[object String]"
console.log(toString.call(true));         // "[object Boolean]"
console.log(toString.call(null));         // "[object Null]"
console.log(toString.call(undefined));    // "[object Undefined]"
console.log(toString.call([]));           // "[object Array]"
console.log(toString.call({}));           // "[object Object]"
console.log(toString.call(new Date()));   // "[object Date]"
console.log(toString.call(/regex/));      // "[object RegExp]"
console.log(toString.call(() => {}));     // "[object Function]"
console.log(toString.call(Symbol()));     // "[object Symbol]"

// 直接使用 Symbol.toStingTag
// 原始值没法用
const map = new Map();
const type = map[Symbol.toStringTag]; // 'Map'

instanceof

object instanceof constructor

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

console.log([] instanceof Array);        // true
console.log({} instanceof Object);       // true
console.log(new Date() instanceof Date); // true
console.log(123 instanceof Number);      // false (基本类型不适用)
console.log("abc" instanceof String);    // false

function myInstanceof(left, right) {
  // 基本类型直接返回 false
  if (
    left === null ||
    (typeof left !== "object" && typeof left !== "function")
  ) {
    return false;
  }

  // 获取对象的原型
  let proto = Object.getPrototypeOf(left);

  while (true) {
    // 到达原型链末端
    if (proto === null) return false;

    // 找到匹配的原型对象
    if (proto === right.prototype) return true;

    // 继续向上遍历原型链
    proto = Object.getPrototypeOf(proto);
  }
}`

总结对比

方法优点缺点
typeof简单快速,适合基本类型无法区分 null、数组、对象等
instanceof可检测自定义对象不适用于基本类型,跨框架失效
Object.prototype.toString精准识别所有类型(推荐)代码稍长
特定方法(如Array.isArray)针对性强适用范围有限

最后


function getType(v) {
    return Object.prototype.toString.call(v).slice(8, -1).toLowerCase();
}

console.log(getType(123));          // "nubmer"
console.log(getType("abc"));        // "string"
console.log(getType(true));         // "boolean"
console.log(getType([]));           // "array"
console.log(getType(null));         // "null"
console.log(getType(Map));          // "function"
console.log(getType(new Map()));    // "map"

JavaScript 数据类型和数据结构