JavaScript 中四种常见的数据类型判断方法

引言

JS 编程中, 正确判断数据类型是必备技能, 也是面试常问的内容。本文将探讨 四种 常用的数据类型判断方法:

  1. typeof
  2. instanceof & isPrototypeOf()
  3. constructor
  4. Object.prototype.toString.call()

通过了解它们的特点和适用范围, 能够更好地处理不同数据类型的情况, 避免出现错误和提升代码质量

一、typeof

typeof 运算符返回一个字符串, 表示操作数的类型, 使用语法: typeof <操作数>

1.1 规则

下表, 是 typeof 针对不同数据类型, 返回的结果值

类型 结果
Boolean "boolean"
String "string"
Number "number"
BigInt "bigint"
Symbol "symbol"
Undefined "undefined"
Null "object"
Function (在 class 也是函数) "function"
其他任何对象 "object"

示例代码如下:

js 复制代码
console.log(typeof true) // boolean
console.log(typeof '123') // string

console.log(typeof 11111) // number
console.log(typeof Math.LN2) // number
console.log(typeof Infinity) // number
console.log(typeof NaN) // number

console.log(typeof BigInt(11111)) // bigint
console.log(typeof Symbol(1111)) // symbol
console.log(typeof undefined) // undefined
console.log(typeof null) // object

console.log(typeof (() => {})) // function
console.log(typeof class {}) // function

console.log(typeof {}) // object 
console.log(typeof []) // object
console.log(typeof /abc/) // object
console.log(typeof new Date()) // object
console.log(typeof new Promise(() => {})) // object

1.2 为什么「typeof null」等于「object」

js 复制代码
// JavaScript 诞生以来便如此
typeof null === "object";
  1. JStypeof null 的结果为 "object", 这是从 JS 的第一版遗留至今的一个 bug
  2. JS 最初的实现中, JS 中的值是由一个表示类型的 标签实际数据值 表示的, 对象的 类型标签0, 由于 null 代表的是空指针, 在大多数平台下值表示为 0x00, 因此, null类型标签0, 因此 typeof null 也就返回了 object
  3. 当然针对这个 BUG 曾有一个 ECMAScript 的修复提案, 但是被拒绝了, 原因是遗留代码太多了, 如果修改的话影响太广, 不如继续将错就错当个和事老

1.3 为什么「typeof (() => {})」等于 「function」

首先我们需要了解一个小知识, 函数是什么? 为什么被调用?

function 实际上是 object 的一个 子类型, 更深点说, 函数是一个可以被调用的对象; 那么它为什么能够被调用呢? 那是因为其内部实现了 [[Call]] 方法, 当函数对象被调用时会执行内部方法 [[call]]

那么回到正题, 为什么 typeof (() => {}) 会返回 function? 这里主要还是要看 ES6typeof 是如何区分函数和对象类型的:

  • 一个对象如果没有实现 [[Call]] 内部方法, 那么它就返回 object
  • 一个对象如果实现了 [[Call]] 内部方法, 那么它就返回 function

1.4 注意事项

  1. 所有使用 构造函数 创建的数据, typeof 都会返回 objectfunction
js 复制代码
const str = new String("String");
const num = new Number(100);

typeof str; // "object"
typeof num; // "object"

const func = new Function();

typeof func; // "function"
  1. typeof 操作符的优先级高于 加法 (+)二进制操作符, 因此, 必要时候记得用括号
js 复制代码
// 括号有无将决定表达式的类型。
const someData = 99;

typeof someData + " Wisen"; // "number Wisen"
typeof (someData + " Wisen"); // "string"

二、instanceof & isPrototypeOf()

JS 中我们有 两种 方式可以判断 原型 是否存在于某个 实例原型链 上, 通过这种判断就可以帮助我们, 确定 引用数据 的具体类型; 需要注意的是该方法 只能用于判断引用数据, 无法判断 基本数据 类型

2.1 instanceof

  1. 介绍: instanceof 运算符用于检测 构造函数prototype 属性是否出现在 某个实例 对象的 原型链

  2. 语法: 实例对象 instanceof 构造函数, 返回一个 Boolean

  3. 示例:

js 复制代码
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

const auto = new Car('Honda', 'Accord', 1998);

auto instanceof Car // Car.prototype 是否在 auto 原型链上, true
auto instanceof Object // Object.prototype 是否在 auto 原型链上, true

2.2 Object.prototype.isPrototypeOf()

  1. 介绍: isPrototypeOf() 方法用于检查一个 对象 是否存在于 另一个对象 的原型链中

  2. 语法: 原型.isPrototypeOf(实例), 返回一个布尔值

  3. 示例:

js 复制代码
function Car() {}

const auto = new Car();

Car.prototype.isPrototypeOf(auto) // Car.prototype 是否在 auto 原型链上, true
Object.prototype.isPrototypeOf(auto) // Object.prototype 是否在 auto 原型链上, true

关于原型、原型链更多知识可查阅 《原型、原型链》

三、根据「constructor」进行判断

constructor 判断方法跟 instanceof 相似, 如下图是 原型实例构造函数 之间的一个关系图, 从图可知, 在 实例对象的原型 中存在 constructor 指向 构造函数, 那么借用这个特性我们可以用于判断 数据 类型

js 复制代码
function Car() {}

const auto = new Car();

auto.constructor === Car // true

不同于 instanceof, 通过该方式既可以处理 引用数据、又能够处理 基本数据

js 复制代码
(123).constructor === Number // true
(true).constructor === Boolean // true
('bar').constructor === String // true

不同于 instanceof, 不能判断 对象父类

js 复制代码
class A {}

class B extends A {}

const b = new B()

b.constructor === B // true
b.constructor === A // false

b instanceof B // true
b instanceof A // true

注意: nullundefined 没有 constructor, 所以它是无法检测 Null undefined

关于原型、原型链更多知识可查阅 《原型、原型链》

四、Object.prototype.toString.call()

Object.prototype.toString.call() 方法返回一个表示该对象的字符串, 该字符串格式为 "[object Type]", 这里的 Type 就是对象的类型

js 复制代码
const toString = Object.prototype.toString;

toString.call(111); // [object Number]
toString.call(null); // [object Null]
toString.call(undefined); // [object Undefined]

toString.call(Math); // [object Math]
toString.call(new Date()); // [object Date]
toString.call(new String()); // [object String]

注意: 对于自定义构造函数实例化出来的对象, 返回的是 [object Object]

js 复制代码
const toString = Object.prototype.toString;
function Bar(){}

toString.call(new Bar()); // [object Object]

默认, 如果一个对象有 Symbol.toStringTag 属性并且该属性值是个字符串, 那么这个属性值, 会被用作 Object.prototype.toString() 返回内容的 Type 值进行展示

js 复制代码
const toString = Object.prototype.toString;

const obj = {
  [Symbol.toStringTag]: 'Bar'
}

toString.call(obj) // [object Bar]

补充: 一个通用方法, 一行代码获取 数据的类型

js 复制代码
const getType = (data) => {
  return Object.prototype.toString.call(data)
    .slice(8, -1)
    .toLocaleLowerCase()
}

五、总结

判断方法 基本类型 引用类型 父类 null undefined
typeof
instanceof & isPrototypeOf()
constructor
Object.prototype.toString.call()
  1. typeof 适合用于判断 基本类型, 特别的是: Null 会返回 objectFunction 返回 function、其余 引用类型 都返回 object
  2. instanceof & isPrototypeOf() 可以用于判断引用数据的类型, 同时可判断 对象父类
  3. constructor 可用于基本类型、引用类型, 但是不可判断 nullundefined, 并且无法判断 对象父类
  4. Object.prototype.toString.call() 万能方法, 对于 JS 中所有类型都能够识别出来, 唯一不足的可能是无法判断 对象父类(但是问题不大)

六、参考


相关推荐
轻口味35 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
晓纪同学2 小时前
QT-简单视觉框架代码
开发语言·qt
威桑2 小时前
Qt SizePolicy详解:minimum 与 minimumExpanding 的区别
开发语言·qt·扩张策略
飞飞-躺着更舒服2 小时前
【QT】实现电子飞行显示器(简易版)
开发语言·qt
明月看潮生2 小时前
青少年编程与数学 02-004 Go语言Web编程 16课题、并发编程
开发语言·青少年编程·并发编程·编程与数学·goweb
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
明月看潮生2 小时前
青少年编程与数学 02-004 Go语言Web编程 17课题、静态文件
开发语言·青少年编程·编程与数学·goweb