当前位置: 首页 > article >正文

简析 JavaScript 判断数据类型的四种方式

前言

JavaScript 作为一门动态语言,其灵活性是把双刃剑。一方面带来了开发的便利性,另一方面也给我们在类型判断时带来了挑战,特别是在处理类型转换和隐式转换的时候

所以本篇文章我们将探讨 JavaScript 中的数据类型判断方式及在实际项目中的应用

数据类型回顾

JavaScript 的数据类型大致分为两类:原始类型和复杂类型

原始类型:

  • undefined:未定义
  • number:数字
  • boolean:布尔值
  • string:字符串
  • null:空值
  • symbol:符号(ES6 新增)
  • bigint:大整数(ES2020 新增)

复杂类型:

  • Object:对象
  • Array:数组
  • Function:函数
  • Date:日期
  • RegExp:正则表达式

类型判断方法详解

typeof 操作符

typeof 是最基础且常用的类型判断方法,使用简单,参阅 MDN 文档

语法:typeof 后面跟一个值或表达式,返回一个字符串,表示操作数的类型

可能返回的数据类型为:undefined、boolean、number、string、object、function、symbol、bigint
// 原始类型判断
typeof "hello"; // "string"
typeof 123; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof 123n; // "bigint"

// 引用类型判断的局限性
typeof []; // "object"
typeof {}; // "object"
typeof null; // "object" (这是一个历史遗留的bug)
typeof new Date(); // "object"
typeof /regex/; // "object"

typeof function () {}; // "function"

注意,typeof 操作符一般用于判断原始类型,对于引用类型的判断存在局限性:

  1. 对引用值的判断有误,一般会返回固定的字符串 object
  2. null 会被错误的判断为 object 类型

instanceof 操作符

instanceof 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上,返回一个布尔值,参阅 MDN 文档

也就是判断一个实例对象是否属于某个构造函数

语法为

object instanceof constructor;

// object:实例对象
// constructor:构造函数

比如下面的例子

const arr = [1, 2, 3];

console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
console.log(arr instanceof Function); // false

一个构造函数的示例:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person = new Person("张三", 20);

console.log(person instanceof Person); // true

在这个例子中,实例对象 person 会通过 __proto__ 属性向上查找原型链,直到找到 Person.prototype 为止,如果找到则返回 true,如果找到顶部 null 都没有找到,则返回 false

实例对象的  __proto__ 属性指向构造函数的  prototype 对象

注意,instanceof 操作符只能用于判断引用类型,不能用于判断原始类型

还存在一个隐患是:如果其原型链被更改,可能导致判断不准确

Object.prototype.constructor

除了 null 和 undefined 以外,所有引用类型都有 constructor 属性,用于返回对象的构造函数,参阅 MDN 文档

我们继续以 instanceof 章节的构造函数示例来看:

所以,更新的图示如下:

实例对象的  __proto__ 属性指向构造函数的  prototype 对象

在图示中,person 的 __proto__ 会等于 Person.prototype,所以 person 实例对象上也有一个 constructor 属性

而且,无论一个变量是通过构造函数方式还是字面量方式,都会有一个 constructor 属性

字面量方式在通过引擎解析时,JavaScript 后台会创建一个相应的原始包装类型对象,暴露出操作原始值的各种方法
const name = "十五";
console.log(name.constructor === String); // true

const age = 18;
console.log(age.constructor === Number); // true

const arr = [1, 2, 3];
console.log(arr.constructor === Array); // true

基本上 constructor 属性能够判断出除了 null 和 undefined 外的所有类型

Object.prototype.toString()

一个通用且准确的类型判断方法

Object.prototype 表示所有对象的原型对象,这个对象上拥有一个 toString()方法,用于返回对象的字符串表示形式

然后搭配 call() 方法,用于改变方法内部的 this 指向

call():函数实例拥有的一个方法,传入的第一个参数可以改变函数内部的  this 指向

基本用法:

const toString = Object.prototype.toString;

const name = "十五";
const age = 18;

console.log(toString.call(name)); // [object String]
console.log(toString.call(age)); // [object Number]

针对性的类型判断方法

Array.isArray()

Array.isArray() 方法用于判断传入的值是否是一个数组

const arr = [1, 2, 3];

console.log(Array.isArray(arr)); // true

Number.isNaN()

Number.isNaN() 方法用于判断传入的值是否为 NaN

NaN:Not a Number,无法表示为数字的值
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("十五")); // false
console.log(Number.isNaN(123)); // false

注意,全局的 isNaN() 与 Number.isNaN() 的区别在于前者会强制进行类型转换,后者则不会(全等判断)

在实践项目中的应用

封装判断类型的工具函数

在真实的项目场景中,我们往往可以统一封装一些工具函数,用于判断类型

比如在 utils 文件夹下新建一个 judge.js 文件,用于编写一些判断类型的工具函数

这里默认你使用了 TypeScript
/**
 * 判断是否为字符串
 * @param value 需要判断的值
 * @returns 布尔值 | true 表示是字符串,false 表示不是字符串
 */
export const isString = (value: unknown): value is string => {
  return typeof value === "string";
};

/**
 * 通用且精确的类型判断
 * @param value 需要判断的值
 * @param type 类型
 * @returns 布尔值 | true 表示符合类型,false 表示不符合
 */
const isType = (value: unknown, type: string) => {
  return (
    Object.prototype.toString.call(value).slice(8, -1).toLowerCase() === type
  );
};

借助第三方库

Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库

它提供了许多有用的工具函数,包括类型判断函数,如 isStringisNumberisArray 等

相关内容拓展:(技术前沿)

近10年间,甚至连传统企业都开始大面积数字化时,我们发现开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。 针对这类问题,低代码把某些重复出现的场景、流程,具象化成一个个组件、api、数据库接口,避免了重复造轮子,极大的提高了程序员的生产效率。 推荐一款程序员都应该知道的软件JNPF快速开发平台,采用业内领先的SpringBoot微服务架构、支持SpringCloud模式,完善了平台的扩增基础,满足了系统快速开发、灵活拓展、无缝集成和高性能应用等综合能力;采用前后端分离模式,前端和后端的开发人员可分工合作负责不同板块,省事又便捷。 体验官网:https://www.jnpfsoft.com 还没有了解低代码这项技术可以赶紧体验学习!


http://www.kler.cn/a/505302.html

相关文章:

  • 小结:路由器和交换机的指令对比
  • 集合帖:区间问题
  • 【WEB】网络传输中的信息安全 - 加密、签名、数字证书与HTTPS
  • 记一次OpenEuler Linux磁盘分区表损坏的数据恢复
  • 【声音场景分类--论文阅读】
  • CAPL如何设置TCP/IP传输层动态端口范围
  • Linux下源码编译安装Nginx1.24及服务脚本实战
  • 【进程与线程】进程的PID
  • 携程API接口详解:如何高效获取景点详情及代码示例
  • 高等数学学习笔记 ☞ 连续函数的运算与性质
  • 分布式数据存储基础与HDFS操作实践(副本)
  • 深度解析Linux中关于操作系统的知识点
  • 浅谈云计算13 | 网络虚拟化
  • Python线性混合效应回归LMER分析大鼠幼崽体重数据、假设检验可视化|数据分享...
  • 如何使用淘宝URL采集商品详情数据及销量
  • python设置键值对
  • Linux网络知识——路由表
  • 少一点If/Else - 状态模式(State Pattern)
  • SQL记录
  • Spring Boot 3.x 整合 Logback 日志框架(支持异步写入)
  • 59_Redis键值设计
  • 音视频文件提供流式传输之HTTP Range 请求
  • 【PHP】双方接口通信校验服务
  • 永久免费不限速下载器支持市面上大部分BT链接
  • vue中 子组件在父组件中因为异步问题导致的的underfind报错问题
  • 通用仓库管理系统开发书 Pyside6 + Sqlite3