前言
在 JS 这样的动态类型语言中,正确地处理不同类型的数据是至关重要的,它不仅仅是确保代码的正确性,还可以提高代码的可读性和可维护性,所以我们应该怎么进行类型判断呢?
本文将探讨 JS 中常用的类型判断方法,包括typeof运算符、instanceof操作符、Object.prototype.toString方法、Array.isArray方法,希望可以帮助到你。
数据类型有哪些?
当然,在进行数据类型判断之前,我们应该了解有哪些数据类型。
原始数据类型:String、Number、Boolean、Symbol、Undefined、Null、BigInt
引用数据类型: Object(引用类型指向一个对象,不是原始值,指向对象的变量是引用变量)
类型判断🔥🔥🔥
1. typeOf
话不多说,直接上代码
javascript
let str = 'hello'
let num = 123
let flag = false
let und = undefined
let nu = null
let big = 123n
let s = Symbol('hello')
let obj = {}
let arr = []
let fn = function() {}
let date = new Date()
// 判断类型
console.log(typeof str); // string
console.log(typeof num); // number
console.log(typeof flag); // boolean
console.log(typeof und); // undefined
console.log(typeof nu); // object 当年遗留下来的bug
console.log(typeof big); // bigint
console.log(typeof s); //symbol
console.log(typeof obj); //object
console.log(typeof arr); //object
console.log(typeof fn); // function
console.log(typeof date); // object
从例子中我们可以看出typeof
是一种运算符,其右侧接一个表达式,然后它返回一个字符串,表示变量的数据类型。
有些时候,typeof
操作符会返回一些令人迷惑的值,比如在判断nu
的数据类型时,它居然返回了一个object
数据类型,难不成是我们代码写错了吗?不,这其实是一个历史遗留问题。在当年,程序员为了区分引用类型
和原始类型
制定了一个规定,所有的引用类型
转换成二进制的时候,前面一定要标注三个零。但是原始类型转
换成二进制时前面一定不能有三个零,而 null
也被用 000 来表示。这意味着,尽管 null
不是对象,但其值标签与对象相同。
总结:
- 对于原始数据类型,除 null 以外,均可以返回正确的结果。
- 对于引用类型,除 function 返回 function,其他一律返回 object 类型。
2. instanceOf
instanceof
是 JS 中的一个操作符,用于检测一个对象是否是另一个对象的实例,是返回true
,否则返回false
。一样的场景感受一下:
javascript
console.log(obj instanceof Object);// true
console.log(arr instanceof Array);// true
console.log(fn instanceof Function);// true
console.log(date instanceof Date);// true
通过这个场景,我们可以猜测出instanceof
是通过原型链查找来进行类型判断的,它只能判断引用数据类型,当我们用instanceof去判断原始类型时,输出值一律为false。
在使用instanceOf
的时候我们需要注意一点,因为它是通过原型链查找来进行类型判断的,所以下面的代码返回值都为true。
javascript
console.log(arr instanceof Array);// true
console.log(arr instanceof Object);// true
所以当我们需要依据返回结果作出一些操作时需要额外注意!!!比如以返回结果作为if的判断条件,决定是走if还是else时。
这时小伙伴们肯定对于instanceOf
是怎么顺着原型链上进行查找感到好奇了吧,接下来我们用段代码来展示一下:
javascript
function instanceOf(L,R) {
let left = L.__proto__ // 获取L的隐式原型
let right = R.prototype // 获取R的显示原型
while(left !== null) { // 顺着原型链进行比较查找
if(left === right) return true
left = left.__proto__
}
return false
}
console.log(instanceOf([],Array)); //true
console.log(instanceOf([],Object)); // true
总结:
- 用于检测一个对象是否是另一个对象的实例
- 只能用于检查对象是否是某个构造函数的实例,不能用于检查原始数据类型。
instanceof
操作符返回一个布尔值
3. Object.prototype.toString
Object.prototype.toString
是 JS 中 Object
原型上的方法,它用于返回一个表示对象的字符串。这个方法通常被用于获取对象的内部 [[Class]] 属性,以便更精确地确定对象的类型。同样我们来个场景感受一下:
javascript
Object.prototype.toString.call(''); // [object String]
Object.prototype.toString.call(6); // [object Number]
Object.prototype.toString.call(true); // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(1000n); // [object BigInt]
Object.prototype.toString.call(undefined); // [object Undefined]
Object.prototype.toString.call(null); // [object Null]
Object.prototype.toString.call(new Function()); // [object Function]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call([]); // [object Array]
Object.prototype.toString.call({}); // [object Object]
我们从这可以看出Object.prototype.toString
是非常精确的进行类型判断,不过我们需要注意的是必须通过Object.prototype.toString.call()
来获取,而不是直接使用Object.prototype.toString()
javascript
console.log(Object.prototype.toString(123)); // [object Object]
console.log(Object.prototype.toString()); // [object Object]
当直接使用Object.prototype.toString()
时,我们返回的都是字符串[object Object]
,所以为什么要使用call()
呢?
在 JS 中,Object.prototype.toString
是一个方法,而不是一个普通的函数。它是定义在 Object.prototype
上的,因此可以被所有对象继承并调用。因此,如果我们想直接调用这个方法,我们可以这样做:
ini
var obj = 123;
var result = obj.toString(); // 直接调用对象的 toString 方法
console.log(obj); // 123
然而,Object.prototype.toString
方法的特殊之处在于,它返回的结果不仅仅取决于调用它的对象,还取决于内部的 [[Class]] 属性。这意味着,直接调用 toString
方法并不能得到我们想要的类型信息。因此,我们需要用 call
或者 apply
来改变方法的执行上下文,以便让它将传入的对象作为自己的上下文,从而获取到正确的类型信息。
ini
var obj = 123;
var result = Object.prototype.toString.call(obj); // 通过 call 方法将 obj 作为上下文传入
console.log(obj); // [object Number]
这是官方对于toString
步骤的描述:
- 如果this值未定义,则返回"[object undefined]"。
- 如果this值为空,则返回"[object null]"。
- 设0为传递this值作为参数调用ToObject(this)的结果。
- 设class为0的内部属性[[class]]的值。
- 返回由"[object" 和 class 和 "]" 三部分组成的字符串.
这时小伙伴应该也会好奇call()
是怎么把toString
掰弯的呢?这里我们也写一段代码来模拟实现一下:
javascript
Function.prototype.myCall = function(context) {
if( typeof this !== 'function') { // this是函数体foo
throw new TypeError('Mycall is not a function')
}
let args = Array.from(arguments).slice(1) //let args = [...arguments].slice(1)
context.fn = this // foo的引用
let res = context.fn(...args) //触发this隐式绑定规则
delete context.fn //用完就删
return res
}
var obj = {a:1}
function foo(x,y) {
console.log(this.a,x+y);
}
foo.myCall(obj,1,2) // 1 3
总结:
- 返回一个字符串。格式通常为
[object 类型]
- 用于获取对象的精确类型,特别适用于引用类型的判断。
- 可以用于检测原始数据类型
4. Array.isArray
Array.isArray()
是 JS 中的一个静态方法,可以直接在 Array
对象上调用。用于确定给定的值是否是一个数组,返回值为:true
或者 false
。例如:
javascript
Array.isArray([]); // true
Array.isArray([1, 2, 3]); // true
Array.isArray(new Array()); // true
Array.isArray({}); // false
总结:
- 它提供了一种更可靠的方式来检查值是否是数组,相比于
instanceof
来说更安全,因为它不会受到原型链影响。 - 在一些旧版本的浏览器中可能不支持该方法,但通常可以通过使用 polyfill 或者其他替代方法来解决。
结尾🌸🌸🌸
类型判断是 JS 开发中的重要一环,通过不断学习和实践,我们可以更好地理解和处理数据。判断数据类型的方法还有很多,我们应该根据实际情况灵活运用。
谢谢各位小伙伴愿意花宝贵的时间阅读这篇文章,如果文章有错误之处,请大家指正,帮助我这位小白成长,谢谢各位小伙伴了!!!!