【必学】浅入深出JS类型判断

前言

当我们在编写JavaScript代码时,了解和正确使用类型判断是非常重要的。JavaScript是一种弱类型语言,变量的类型可以动态改变,因此在处理数据时,我们经常需要进行类型判断以确保代码的正确性和可靠性。

本文将带领读者从基础到高级,深入剖析JavaScript中的类型判断机制,揭开这一重要主题的面纱。

数据类型

JavaScript有七种原始数据类型与四种引用类型,原始数据类型分别是Undefined、Null、Boolean、Number、String、Symbol和BigInt,引用类型分别是对象、数组、函数、日期。

1. typeof

在进行类型判断时,我们可以使用typeof操作符来获取变量的类型。

原始数据类型

js 复制代码
let str = 'hello';
console.log(typeof str);  // "string"

let num = 123;
console.log(typeof num);  // "number"

let flag = true;
console.log(typeof flag); // "boolean"

let und = undefined;
console.log(typeof und);  // "undefined"

let nu = null;
console.log(typeof nu);   // "object"

let big = 123n;
console.log(typeof big);  // "bigint"

let s = Symbol('hello');
console.log(typeof s);    // "symbol"

引用类型

js 复制代码
let obj = {};
console.log(typeof obj);  // "object"

let arr = [];
console.log(typeof arr);  // "object"

let fn = function(){};
console.log(typeof fn);   // "function"

let date = new Date();
console.log(typeof date); // "object"

我们发现typeof null 返回的是object,这是一个历史遗留问题,与语言本身的设计和演变有关。在 JavaScript 的早期版本中,变量的值是由存储在变量存储空间中的标记位来表示的。在 JavaScript 中,所有的对象都表示为32位的字(words),而其中的第一个位被用作类型标签。

  • 对象类型的类型标签是 000。
  • null 被认为是一个空对象指针,因此它的类型标签也是 000。

因此,typeof null 返回 "object" 是因为在检查变量类型时,JavaScript 会读取存储在变量存储空间中的类型标签,而 null 的类型标签被解释为对象类型。

虽然这个行为是历史遗留问题,但为了保持向后兼容性,JavaScript 的设计者选择保留了这个特性。在现代的 JavaScript 中,为了准确判断变量是否为 null,推荐使用严格相等运算符 ===:

js 复制代码
console.log(nu === null) //true

除此之外,我们发现引用类型只能将函数判断为function、将对象判断为object,而数组跟函数也判断为object。所以我们还需要再找一个能进一步判断引用类型的操作符。


2. instanceof

instanceof 操作符用于检查对象是否是特定类(构造函数)的实例。它通过检查对象的原型链来确定对象的类型。如果对象是指定类的实例,则返回 true,否则返回 false。

js 复制代码
let obj = {}
console.log(obj instanceof Object); // true 

let arr = []
console.log(arr instanceof Array); // true 

let fn = function(){}
console.log(fn instanceof Function); // true 

let date = new Date()
console.log(date instanceof Date); // true 

所以我们可以通过instanceof,再结合构造函数来判断引用类型。

于是我们可以手写一个instanceof:

js 复制代码
function instanceOF(L, R) {
    let left = L.__proto__;    // 初始化变量 left 为实例对象 L 的隐式原型
    let right = R.prototype;    // 初始化变量 right 为构造函数 R 的显示原型 
    while (left !== null) {    // 迭代访问左操作数的原型链,如果不为空则进循环
        if (left === right) {    // 检查当前对象的隐式原型是否与构造函数的显示原型相等
            return true;    // 如果相等,返回 true,表示这个实例对象是这个构造函数创建的 
        } 
        left = left.__proto__;    // 移动到链中的下一个隐式原型 
    } 
    return false;     // 如果没有找到匹配,返回 false 
}
//举例:
console.log(instanceOF([],Array));//true

但是我们在运用instanceof的时候,还会出现一种情况:

js 复制代码
let arr = []
console.log(arr instanceof Object); // true

我们发现,数组也可以被判定为对象,所以当我们要判断一个数据类型是不是对象的时候,用instanceof就不妥,因为数组可以被识别成对象。导致我们判断错误。

那有没有能够直接判断类型的方法?

3. Object.prototype.toString()

官方定义: Object.prototype.toString()当调用toString方法时,将执行以下步骤:

  1. 如果this值未定义,则返回"[object undefined]"。
  2. 如果this值为空,则返回"[object null]"。
  3. 让o作为传递this值作为参数的object调用的结果。
  4. 设class为o的内部属性[[Class]]的值。
  5. 返回三个字符串 "[object " 和 class 和 "]" 连接后的String值。

以上为官方规定,在这里就不过多解释,我们直接用就行了。(参考原文Annotated ES5)

js 复制代码
let number = 42;
console.log(Object.prototype.toString.call(number)); // "[object Number]"

let str = "Hello";
console.log(Object.prototype.toString.call(str)); // "[object String]" 

let bool = true;
console.log(Object.prototype.toString.call(bool)); // "[object Boolean]"

console.log(Object.prototype.toString.call(null));//'[object Null]'

console.log(Object.prototype.toString.call(undefined));//'[object Undefined]'

let bigint = 123n
console.log(Object.prototype.toString.call(bigint));//'[object BigInt]'

let symbol = Symbol('hello')
console.log(Object.prototype.toString.call(symbol));//'[object Symbol]'

let array = [];
console.log(Object.prototype.toString.call(array)); // "[object Array]"

let date = new Date();
console.log(Object.prototype.toString.call(date)); // "[object Date]" 

var obj = {};
console.log(Object.prototype.toString.call(obj));//'[object Object]'

let func = function() {};
console.log(Object.prototype.toString.call(func)); // "[object Function]"

我们可以用这个方法判断然后数据类型。在这里我们通过使用 call 方法,可以将 this 设置为任何我们想要检查的对象,从而获取该对象的准确类型信息。

我们可以稍加改进,让这个方法更容易为我们所用:

js 复制代码
var s ='thisisstring'

function isType(s) {
    return Object.prototype.toString.call(s).slice(8,-1)
}

if(isType === 'String'){
    //xxx
}

通过isType函数,我们就可以获取变量 s 的类型,并与字符串 'String' 进行比较,其中slice(8,-1)用于截取类型字符串,去除 "[object " 和 "]" 部分。

最后

通过本文的学习,我们不仅深入了解了基本的 typeof 操作符和 instanceof 操作符,还探讨了更为精准的 Object.prototype.toString 方法。这些工具不仅帮助我们在编码过程中避免潜在的错误,还为处理各种复杂的数据结构提供了可靠的手段。

我的Gitee: CodeSpace (gitee.com)

技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!

相关推荐
lovingsoft3 分钟前
Chrome Lighthouse 详解
前端·chrome
Qlly13 分钟前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝17 分钟前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦17 分钟前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡38 分钟前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI44 分钟前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
汉堡大王95271 小时前
单次输出拉到100万Token:拆完 Gemini 4 Argon 的续写协议,才看懂谷歌这7个月在憋什么
前端·人工智能·后端
看浪的路人1 小时前
第9讲:大模型应用监控与可观测性——OpenTelemetry + Prometheus + Grafana 全链路追踪
java·前端·spring
内存过载1 小时前
用表格模拟甘特图:项目排期的土办法
前端·低代码
葡萄城技术团队1 小时前
用 SpreadJS 数据验证实现省市区三级联动
前端