JS类型检测大全:从零基础到高级应用

文章目录

    • [1. typeof 操作符](#1. typeof 操作符)
      • [typeof null 为什么是 object](#typeof null 为什么是 object)
    • [2. `instanceof` 操作符](#2. instanceof 操作符)
    • [3. `Object.prototype.toString.call()`(最准确的)](#3. Object.prototype.toString.call()(最准确的))
    • [4. Array.isArray()](#4. Array.isArray())
    • [5. `constructor` 属性](#5. constructor 属性)
    • 总结

在JavaScript中,有多种方法可以用来检测数据类型。每种方法都有其特定的用途和局限性。下面是几种常用的类型检测方法及其特点:

1. typeof 操作符

typeof 可以用来检测基本数据类型(除了nullundefined之间的区分)。

  • 优点:简单易用。
  • 缺点:无法准确区分 null数组,对象,都会返回 "object"。其他判断都正确
js 复制代码
console.log(typeof ½); // "number"
console.log(typeof 'str'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" 
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"

typeof null 为什么是 object

在最初的 JS 实现中,typeof 操作符的设计目的是返回一个字符串,指示未经计算的操作数的类型。然而,在处理null时,由于null最初被设计为表示"无对象",因此将其类型视为 "object"。这个决定导致了typeof null返回 "object"

解决办法

  1. 使用严格相等运算符(===
js 复制代码
if (value === null) {
  console.log("这是一个 null");
}
  1. 使用 Object.prototype.toString.call()
    这是最准确的方法,可以明确地区分 null 与其他类型。
js 复制代码
if (Object.prototype.toString.call(value) === "[object Null]") {
  console.log("这是一个 null");
}
  1. 自定义类型检查
    写一个函数用来检测
js 复制代码
function getType(value) {
  if (value === null) {
    return "null";
  }
  return typeof value;
}

console.log(getType(null)); // "null"
console.log(getType(42)); // "number"
console.log(getType("hello")); // "string"

2. instanceof 操作符

instanceof 用来检查一个对象在其原型链中是否存在一个构造函数的prototype属性

  • 优点:可以用来区分不同的引用类型。
  • 缺点:不能用来检测基础类型。跨iframe使用时可能会出现问题。
js 复制代码
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function); // true

3. Object.prototype.toString.call()(最准确的)

这是最可靠的一种类型检测方法,可以准确地区分所有类型,包括基础类型和引用类型。

使用Object对象的原型方法toString方法来判断

优点:非常准确,支持所有类型。

缺点:语法稍微复杂一点。

  • 基本类型
js 复制代码
console.log(Object.prototype.toString.call(1)); // "[object Number]"
console.log(Object.prototype.toString.call('str')); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(BigInt(123456789012345678901234567890n))); // "[object BigInt]"
  • 引用类型
js 复制代码
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call(function() {})); // "[object Function]"
console.log(Object.prototype.toString.call(new Date())); // "[object Date]"
console.log(Object.prototype.toString.call(new RegExp("abc"))); // "[object RegExp]"
console.log(Object.prototype.toString.call(new Map())); // "[object Map]"
console.log(Object.prototype.toString.call(new Set())); // "[object Set]"
console.log(Object.prototype.toString.call(new WeakMap())); // "[object WeakMap]"
console.log(Object.prototype.toString.call(new WeakSet())); // "[object WeakSet]"
console.log(Object.prototype.toString.call(new Error())); // "[object Error]"
  • 特殊对象
js 复制代码
console.log(Object.prototype.toString.call(Math)); // "[object Math]"
console.log(Object.prototype.toString.call(JSON)); // "[object JSON]"
console.log(Object.prototype.toString.call(Promise.resolve())); // "[object Promise]"
  • 自定义检测方法 -便捷使用
js 复制代码
function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

console.log(getType(42)); // "number"
console.log(getType("Hello, World!")); // "string"
console.log(getType(true)); // "boolean"
console.log(getType(undefined)); // "undefined"
console.log(getType(null)); // "null"
console.log(getType(Symbol("symbol"))); // "symbol"
console.log(getType({})); // "object"
console.log(getType([])); // "array"
console.log(getType(function() {})); // "function"
console.log(getType(new Date())); // "date"
console.log(getType(new RegExp("abc"))); // "regexp"
console.log(getType(new Map())); // "map"
console.log(getType(Promise.resolve())); // "promise"

4. Array.isArray()

专门用于检测是否为数组。

优点:简单明了,专用于数组检测。

缺点:只能用于数组。

js 复制代码
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false

5. constructor 属性

通过检查对象的constructor属性来确定其构造函数。

优点:可以用于大多数引用类型。

缺点:constructor 对象访问它的构造函数,如果创建一个对象改变它的原型,则可能不准确。对于基础类型无效。

js 复制代码
console.log((2).constructor == Number); //true
console.log((true).constructor == Boolean); //true
console.log(("string").constructor == String); //true

console.log(([]).constructor === Array); // true
console.log(({}).constructor === Object); // true
console.log((function(){}).constructor === Function); // true

// 改变原型之后
function Fn(){}

Fn.prototype  = new Array();
var f= new Fn();

console.log(f.constructor === Fn);//false
console.log(f.constructor === Array);//true

总结

  • 对于基础类型,推荐使用 typeof 或 Object.prototype.toString.call()。
  • 对于引用类型,尤其是需要区分具体类型时,Object.prototype.toString.call() 是最佳选择。
  • 如果只需要判断是否为数组,Array.isArray() 是最直接的方法。
  • instanceof 在某些情况下也很有用,特别是当你需要检查对象是否是由特定构造函数创建的时候。
相关推荐
泯泷5 小时前
那段文字是谁删的?Yjs 14 正式版之前,一套删除归属方案的实现与边界
前端·javascript·算法
hold?fish:palm6 小时前
34 合并K个升序链表
javascript·算法·链表
C++ 老炮儿的技术栈6 小时前
我们在设计tcp协议时,要传一个字符串过去,报文:头十长度十内容,是否要把‘\0‘也填入,长度是否包含‘\0‘
开发语言·数据结构·c++·mfc·c
传奇开心果编程7 小时前
【Rust入门练中学】第2课:变量、可变性与常量
开发语言·学习·rust
zr想努力7 小时前
从0开始配置Perforce4环境
开发语言
野槐8 小时前
前端项目优化(有了我,会发生...)
前端
幸运小圣8 小时前
PointerEvent 常用属性与事件整理【JavaScript】
开发语言·javascript·ecmascript
aa小小9 小时前
【无标题】
前端
长谷深风1119 小时前
评测AI Agent:三种裁判各司其职
java·大数据·开发语言·人工智能·ai agent
边境悍匪9 小时前
蜗牛学苑 Java 智能体学习 Day42|项目周开发技术汇总 1 思维导图复盘
java·开发语言·spring boot·学习·spring