JS 中如何进行类型判断

在 JavaScript 中,很多时候我们需要对数据进行类型的判断;用于类型判断的方法也常常会被面试官给问到,那么今天我们就来探究一下在 JS 中是如何进行类型判断的,以及有哪些方法可以用于类型的判断。

谈到类型的判断,我们先来回想一下 JS 中的数据类型有哪些?

数据在v8中的存储

原始类型

在 JS 中,我们可以把原始类型分为以下五种;

  • Number
  • String
  • Boolean
  • undefined
  • null

正是因为原始类型的值所占用内存都比较小 ,所以在 JS 中,原始类型都是被存储在调用栈中的

引用类型

在 JS 中,常见的引用类型如下;

  • Object
  • Array
  • Function
  • Date
  • RegExp

引用类型与原始类型不同,引用类型通常占用的内存都比较大

调用栈为了维护函数之间的调用关系且要保证v8引擎的执行效率,所以调用栈的存储空间比较小

如果把引用类型也储存在调用栈中,就很容易造成爆栈的现象;所以引用类型一般是储存在堆这种数据结构中的 ,并且将堆中的引用地址存在调用栈当中

数据的类型判断

typeof

在 JS 中,给我们打造了这样一种方法可以进行类型的判断,那就是 typeof;先来看下面一段代码

ini 复制代码
let str = 'hello'
let num = 123
let flag = false
let un = undefined
let nu = null

// 原始类型中,只有null会被typeof 判断成 object
console.log(typeof str);
console.log(typeof(num));
console.log(typeof(flag));
console.log(typeof(un));
console.log(typeof(nu));  // object

我们用 typeof 去判断原始类型时,可以看到 typeof 方法判断前面四种原始类型都能正确判断,而判断 null 时却输出了 object

这是因为 typeof 方法被打造出来的时候,它在判断时会把数据转换成二进制 ,而在当时的代码设定中,只要数据转换成二进制后的前三位只要是 0 ,那就会被判断为是 object ,正好 null 这种原始类型转换为二进制后是 000000 ,这就恰好导致了 typeof 会将null判断成是 object

再来看,我们用 typeof 对引用类型进行判断;

vbnet 复制代码
let obj = {}
let arr = []
let fn = function (){}
let date = new Date()

// 引用类型中,typeof 只能正确判断function这个引用类型,其他都默认是object
console.log(typeof(obj)); 
console.log(typeof(arr));    // object
console.log(typeof(fn));     // function
console.log(typeof(date));   // object

在上面的代码中,typeof 又可以判断 function 这种引用类型了。

当初 typeof 这个被打造出来时,也并不是用来判断引用类型的,typeof 就是被打造出来判断原始类型的因为引用类型转二进制后大部分的前三位都是 0 ,这才导致 typeof 会把绝大多数的引用类型判断成是 object,而 function 也是一个特例,唯一一个能被 typeof 正确判断的引用类型

了解到 typeof 方法的机制之后,我们可以去封装一个简单的判断对象的方法;只要是引用类型就返回objectfunction除外)

javascript 复制代码
function isObject(obj) {
    if (typeof obj === 'object' && obj !== null) {
        return true
    }
    return false
}

console.log(isObject({}));

instanceof

我们再来看 instanceof 这个方法,也是可以用于类型的判断;instanceof 的用法是判断左边是否隶属于右边:来看下面代码

javascript 复制代码
let str = 'hello'
let num = 123
let flag = false
let un = undefined
let nu = null

console.log(str instanceof String);
console.log(num instanceof Number);
console.log(flag instanceof Boolean);

可以看到 instanceof不能判断原始类型;再来看引用类型:

javascript 复制代码
let obj = {}
let arr = []
let fn = function (){}
let date = new Date()

console.log(obj instanceof Object);
console.log(arr instanceof Array);
console.log(fn instanceof Function);
console.log(date instanceof Date);

当我们用 instanceof 判断引用类型时,又能够准确的判断出来,这是为什么呢?

其实这是因为,instanceof 方法是通过原型链查找的 ,每个引用类型 都可以看作是通过 new 和构造函数的方式创建出来的实例 ,这时 instanceof 就会判断左边实例对象的隐式原型(也就是构造函数的显式原型prototype 属性)是否出现于右边的原型链上

javascript 复制代码
console.log(arr instanceof Object); // 通过原型链查找到了object
console.log(1 instanceof Number); // 原始值
let num1 = new Number(1)
console.log(num1 instanceof Number); // Number 包装类对象

知道了 instanceof 的原理后,我们也可以去手动实现一下它的功能;

javascript 复制代码
// function myInstanceof(L, R) {
//     // 如果对象的原型不存在,则对象不是构造函数的实例
//     if(L == null || L.__proto__ == null){
//         return false
//     }
//     // 检查对象的原型是否与构造函数的 prototype 相同
//     if (L.__proto__ === R.prototype) {
//         return true
//     }
//     // 递归地检查对象的原型的原型
//     return myInstanceof(L.__proto__, R)
// }

// 函数 myInstanceof 用于检查对象 L 是否是构造函数 R 的一个实例
function myInstanceof(L, R) {
    // 当 L 不等于 null 时,继续执行循环。这是因为 null 是原型链的末端,表示不再有父类
    while (L!== null) {
        // 检查对象 L 的原型链中的原型(__proto__)是否等于构造函数 R 的原型(prototype)。如果两者相同,意味着对象 L 是构造函数 R 的实例
        if (L.__proto__ == R.prototype){
            return true
        }
        // 将对象 L 替换为其原型链中的下一个原型(__proto__),以便继续检查其是否是构造函数 R 的实例
        L = L.__proto__
    }
    return false
}

Object.prototype.toString.call()

基本在每个数据类型的身上都会有一个方法,那就是toString(),但不同类型的数据身上的toString方法也是不同的;

vbscript 复制代码
let a = {}
let b =[1,2,3]
let c = 1
let d = '123'
let e = true

console.log(a.toString());
console.log(b.toString());
console.log(c.toString());
console.log(d.toString());
console.log(e.toString());

对此,toString()方法,可以分为以下;

  1. 对象的 toString()
  2. 数组的 toString():将数组中的元素用逗号的方式拼接成字符串
  3. 其他的 toString():直接将值修改成字符串字面量

Object.prototype.toString()

我们再来看看对象原型上的toString方法是什么样的?

在官方文档的介绍中,我们可以得出Object.prototype.toString()的基本用法;

  • Object.prototype.toString()
  1. 如果 toString 接收的值是 undefined,则返回"[object Undefined]"。

  2. 如果 toString 接收的值是 null,则返回"[object Null]"。

  3. 如果接收的既不是 undefined 也不是 null 的话,就调用 ToObject(x)x 转为对象 ,此时得到的对象内部一定拥有一个属性[[class]],而该属性[[class]]的值就是 x 的类型

    • 设 class 是 [[class]] 的值
    • 返回由"[object"class"]" 拼接得到的字符串

这也是为什么对象的toString方法会返回[object Object]的原因。

那知道了Object.prototype.toString()方法的机制之后,我们就可以利用这个机制去进行类型的判断;

javascript 复制代码
let a = {}
let b =[]

console.log(Object.prototype.toString(a));

console.log(Object.prototype.toString.call(b)); // this 指向

正是因为,Object.prototype.toString()在接收到非undefinednull的值后,就会返回一个带有自身类型的字符串 ,所以我们就可以利用.call方法去让传进来的值触发掉Object.prototype.toString()这个方法。这样我们也能达成一个类型判断的效果。

通过这个方法,我们也能手搓出一个type方法来返回数据类型;

javascript 复制代码
function type (x) {
    let res = Object.prototype.toString.call(x)
    return res.slice(8, -1) // 从后往前,最后一个不要
}

console.log(type('123'));

Array.isArray()

最后,要介绍一个特殊的类型判断的方法 Array.isArray(),它只能用于判断类型是否为数组

ini 复制代码
let arr = [];
let obj = {};
let n = 123;

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

console.log(Array.isArray(obj));

console.log(Array.isArray(n));

以上就是,在 JS 中能够进行数据类型判断的方法了,觉得有用的话就点点赞吧!

相关推荐
gqkmiss20 分钟前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃26 分钟前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰30 分钟前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter
Viktor_Ye37 分钟前
高效集成易快报与金蝶应付单的方案
java·前端·数据库
hummhumm39 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
乐闻x1 小时前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化
一条晒干的咸魚1 小时前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
花海少爷1 小时前
第十章 JavaScript的应用课后习题
开发语言·javascript·ecmascript
Amd7941 小时前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You2 小时前
09 —— Webpack搭建开发环境
前端·webpack·node.js