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 中所有类型都能够识别出来, 唯一不足的可能是无法判断 对象父类(但是问题不大)

六、参考


相关推荐
码农幻想梦1 小时前
实验九 视图的使用
前端·数据库·oracle
喵手1 小时前
Java 与 Oracle 数据泵实操:数据导入导出的全方位指南
java·开发语言·oracle
硬汉嵌入式2 小时前
H7-TOOL的LUA小程序教程第16期:脉冲测量,4路PWM,多路GPIO和波形打印(2024-10-25, 更新完毕)
开发语言·junit·小程序·lua
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
开心工作室_kaic3 小时前
ssm010基于ssm的新能源汽车在线租赁管理系统(论文+源码)_kaic
java·前端·spring boot·后端·汽车
Python私教3 小时前
Flutter颜色和主题
开发语言·javascript·flutter
代码吐槽菌3 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
Ws_3 小时前
蓝桥杯 python day01 第一题
开发语言·python·蓝桥杯
zdkdchao3 小时前
jdk,openjdk,oraclejdk
java·开发语言
神雕大侠mu4 小时前
函数式接口与回调函数实践
开发语言·python