面试官:请你谈谈JS中几种常见的类型判断方法
前言
在开发的过程中,经常会遇到数据类型判断的场景,在JavaScript中常见的对类型进行判断的方法有:typeof、instance、Object.prototype.toString
。在js中这些方法都能够判断数据类型,但是这些方法的实现原理和适用场景各不相同,本文我将带大家深入探讨它们的使用方法和底层原理。
typeof
我们知道,在JavaScript中数据分为两大类--原始数据类型和引用数据类型。
typeof判断原始数据类型
使用typeof判断原始数据类型时,可以判断除null之外
的所有原始类型。
如以下示例代码:
// 原始数据类型
let s = '123'; // String
let n = 123; // number
let f = true; // boolean
let u = undefined; // undefined
let nu = null; // null
// es6新增的
// 创建一个独一无二的值
let sy = Symbol(123) // symbol
// 大整形数
let big = 1234n; // bigint
console.log(typeof s); // string
console.log(typeof n); // number
console.log(typeof f); // boolean
console.log(typeof nu); // object
console.log(typeof sy); // symbol
console.log(typeof big); // bigint
注意看。为什么使用typeof判断null的数据类型时输出的是object?其实这是一个历史遗留问题,在很早以前,计算机底层执行typeof是通过将值转化为二进制后判断其二进制前位是否为0来判断是不是object,当提出null时判断位数已经用完,所以null就被归为object那类。
typeof判断引用数据类型
使用typeof判断引用数据类型时,除了function
其他所有的引用类型都会被判断成object
// 引用数据类型
let obj = {}
let arr = []
let fn = function () { }
let date = new Date()
console.log(typeof obj); // object
console.log(typeof arr); // object
console.log(typeof fn); // function
console.log(typeof date); // object
instanceof
JavaScript中,可以使用instanceof来判断引用数据类型,不能用来判断原始数据类型。下面我将来为大家介绍instanceof判断数据类型的使用方法以及instanceof的底层原理。
instanceof的使用方法
let obj = {}
let arr = []
let fn = function () { }
let date = new Date()
let s = '123'; // String
let num = 123;
let bool = true;
// 引用数据类型的判断
console.log(obj instanceof Object); // true
console.log(arr instanceof Array); // true
console.log(fn instanceof Object); // true
console.log(fn instanceof Function); // true
console.log(date instanceof Object);// true
console.log("-----------------------")
// 原始数据类型的判断
console.log(s instanceof String); // false
console.log(num instanceof Number); // false
console.log(bool instanceof Boolean); //false
instanceof
不能直接用来判断 JavaScript 中的原始数据类型(也称为基本数据类型),如 string
、number
、boolean
、undefined
、null
、symbol
和 bigint
。instanceof
操作符是用来检查一个对象是否在一个构造函数的原型链上,即判断一个对象是否是某个构造函数的实例。
原始数据类型不是对象,它们不是通过构造函数实例化产生的,因此没有原型链的概念,所以使用 instanceof
判断原始数据类型会始终返回 false
。
instanceof的底层原理
instanceof
的实现原理基于 JavaScript 的原型链。它的主要作用是检查一个对象是否在另一个对象的原型链上,也就是说,它会查看一个对象的原型是否等于或继承自另一个对象的原型。具体步骤如下:
-
获取右操作数的原型: 首先,
instanceof
获取右侧构造函数(通常是类或函数)的.prototype
属性,这个属性通常是一个对象,代表了实例化后的对象将继承的属性和方法。 -
遍历左操作数的原型链: 接着,
instanceof
开始从左侧对象的__proto__
属性开始(在严格模式下,某些环境可能会使用Object.getPrototypeOf
函数来获取原型),__proto__
指向了该对象的构造函数的原型。 -
比较原型: 然后,
instanceof
检查当前对象的原型是否等于右侧构造函数的原型。如果相等,返回true
,表示左侧对象是右侧构造函数的实例。如果不等,则继续沿着左侧对象的原型链向上查找,通过检查__proto__
的__proto__
,直到找到null
(表示到达原型链的顶部),此时返回false
。 -
处理特殊情况:
- 如果左侧对象是
null
,instanceof
返回false
,因为null
没有原型。 - 如果右侧不是一个函数,
instanceof
通常会抛出错误,因为只有函数才能有.prototype
。
- 如果左侧对象是
上述步骤为instanceof的底层实现原理,大家看起来是不是有点懵?接下我将用代码的形式手写instanceof的实现原理并用图文的形式给大家展示。
手写instanceof,请思考以下代码(从原型链的角度思考)
:
// instanceof 的原理
function myinstanceof(L, R) {
while (L != null) {
if (L.__proto__ === R.prototype) {
return true;
}
L = L.__proto__;
}
return false;
}
myinstanceof([], Array) // true
myinstanceof([], Object) // true
执行过程:
- 初始化:
L
同样是一个空数组实例,R
是Object
构造函数。- 原型链遍历:数组的直接原型
L.__proto__
是Array.prototype
,但这不等于Object.prototype
。因此,继续向上遍历。- 找到关联:
Array.prototype
的__proto__
是Object.prototype
,这意味着数组的原型链最终指向了Object.prototype
。因此,满足条件,返回true
。这表明所有数组(以及大多数JavaScript对象)也是Object
的实例,因为它们继承自Object.prototype
。
Object.prototype.toString.call(this)
Object.prototype.toString.call(this)
是 JavaScript 中一种常用的技巧,用于获取当前上下文(this
)的精确类型表示。这个表达式的工作原理和用途如下:
原理
-
Object.prototype.toString
方法:toString
方法是每个 JavaScript 对象从Object.prototype
继承而来的方法。默认情况下,当直接调用一个对象的toString
方法时(例如,obj.toString()
),它会返回一个表示该对象的字符串。对于普通对象,这通常是[object Object]
。
-
覆盖与默认行为:
- 许多内置对象(如数组、函数、日期等)重写了
toString
方法,以提供更有用的信息。但是,这些重写的版本通常关注于对象的内容,而不是其类型。
- 许多内置对象(如数组、函数、日期等)重写了
-
Object.prototype.toString
的特殊性:- 特别地,
Object.prototype.toString
方法在没有被重写的情况下,能够返回一个表示对象类型的标准字符串格式,即[object Type]
,其中Type
是对象的内部类型名称。这对于准确识别对象类型非常有用。
- 特别地,
-
使用
call
方法:call
方法属于Function.prototype
,它允许你改变函数调用的上下文(即this
值),并立即调用该函数。在这里,call(this)
使得Object.prototype.toString
在当前上下文(this
)中执行,从而获取该上下文的类型信息。
用途
-
类型检测:
- 通过
Object.prototype.toString.call(this)
,可以准确检测this
指向的对象的类型,包括但不限于"object"
,"array"
,"function"
,"date"
,"regexp"
等。这对于编写兼容性强、精度高的类型检查代码非常有用,尤其是在typeof
无法提供足够信息时(例如,typeof []
返回"object"
而不是"array"
)。
- 通过
本篇文章就到此为止啦,希望通过这篇文章能对你了解JavaScript类型检测
有所帮助,本人水平有限难免会有纰漏,欢迎大家指正。如觉得这篇文章对你有帮助的话,欢迎点赞收藏加关注,感谢支持🌹🌹。
转载自:https://juejin.cn/post/7371000326131171378