写代码就像搭积木,而类型判断就是确保每块积木都能稳稳搭上去的关键。在JavaScript
的世界里,数据类型多种多样,有时候我们得搞清楚这些数据的“身份”,才能让程序正常运行。类型判断就像是给数据“验明正身”的过程,它帮助我们确保数据是按照我们预期的方式被处理的。掌握JavaScript
的类型判断,能让你的代码更加健壮,减少出错的可能性。接下来,我们就来一起探索JavaScript
的类型判断,看看它是如何帮助我们的代码更加可靠和高效的。
数据类型
在学习判断类型之前,我们先回忆一下有哪些数据类型
原始类型
js 代码解读复制代码Number
String
boolean
undefined
null
bigInt
Symbol
引用类型
js 代码解读复制代码function
Object
Array
Date
类型判断
实例
js 代码解读复制代码function add(x,y){
return x+y;
}
console.log(add(2,'3'));
像上面的代码,如果我们是想求两个数字的和,但这时候传进去的有数字字符串,我们还能得到两数之和吗?看看代码执行结果
执行结果字体是白色的,说明是字符串,与我们想要的效果不一样,因此如果用户传入的是字符串,我们要先将字符串变为number
类型,所以在函数里,我们要进行一个判断操作
js 代码解读复制代码function add(x,y){
if(typeof(x)=='number'&&typeof(y) =='number'){
return x+y;
}
else{
return Number(x)+Number(y);
}
}
console.log(add(2,'3'));
用typeof
来判断是不是都为number
类型,如果不是就将x,y
都转换为number
类型,这样就能得到我们想要的两数相加的效果了
typeof
js 代码解读复制代码let a = 1
// console.log(typeof a); //Number
a = 'hello'
// console.log(typeof a); //String
a = true
// console.log(typeof a); //boolean
a = null
// console.log(typeof a); //object
a = undefined
// console.log(typeof a); //undefined
a = Symbol(1)
// console.log(typeof a); //symbol
a = 123n
// console.log(typeof a); //bigint
a = []
// console.log(typeof a); // object
a = {}
// console.log(typeof a); //object
a = function () {}
// console.log(typeof a); // function
a = new Date()
// console.log(typeof a); //object
可以看得出来,typeof
可以判断除了null
以外的所有原始类型,为什么不能判断null
,在这篇文章中有解释(juejin.cn/post/744071…)
而引用类型除了函数以外都会判断为object
,所以这里对象类型判断准确可以说它是蒙的,因为它会将引用类型无脑判断为object
,因此可以看得出来,typeof
可以准确判断除了null
之外的所有原始类型,不能判断引用类型(除了function
),function有很多功能,做了特殊处理。那typeof
只能判断原始类型,我们想判断引用类型怎么办呢官方有没有打造一个判断引用类型的方法呢,当然是有的,叫instanceof
instanceof
instancef的使用
js 代码解读复制代码console.log({} instanceof Object);
console.log([] instanceof Array);
console.log(function () { } instanceof Function);
console.log(new Date() instanceof Date);
console.log('String' instanceof String);
console.log(123 instanceof Number);
console.log(true instanceof Boolean);
看上面的代码,我们用instanceof
来判断类型,instanceof
翻译的意思就是‘隶属于’的意思,左边放值,右边放类型,然后让我们来看看它的输出结果
可以看到引用类型可以成功判断,但是原始类型无法进行判断,那看看之前那个bug-null
能不能成功判断呢
js 代码解读复制代码console.log(null instanceof Null)
可以看到报错了,所以是无法判断null
的类型
那我们将引用类型后面全部放object
会怎么样
js 代码解读复制代码console.log({} instanceof Object);
console.log([] instanceof Object);
console.log(function () { } instanceof Object);
console.log(new Date() instanceof Object);
可以看到,还是都为true
,不过我们也无法反驳,因为引用类型确实也可以说它是对象。那我们要来了解一下instanceof
的判断原理
instanceof的判断原理
js 代码解读复制代码function Bus() { }
let bus = new Bus()
console.log(bus instanceof Bus);
我们看上面的代码,我们创建一个函数Bus
然后创建出它的一个实例对象,再用instanceof
去判断这个实例对象是否属于这个函数。
可以看到它能判断出这个实例对象是否由构造函数Bus
产生的
那我们再创建一个car
函数
js 代码解读复制代码function car(){}
Bus.prototype=new car();
function Bus() { }
let bus = new Bus()
console.log(bus instanceof car);
那现在来判断bus
是不是属于car
,我们来看看执行结果
可以看到,依旧是属于的,那为什么呢,首先我们知道实例对象bus的隐式原型等于创建它的构造函数Bus的显示原型,所以我们可以判断出bus
属于Bus
,那为什么bus
还会判断出属于car
, bus.__ proto__
等于car.prototype
吗, 当然不是但是Bus.prototype
等于car创建出来的实例对象,Bus.prototype.__ proto __
等于car.prototype
,而 bus. __ proto __
=Bus.prototype,
所以bus. __ proto __ . __ proto __
等于car.prototype
,因此bus
也是属于car
的,就和翻族谱一样,那作为第一页的object
呢,bus
会属于它吗,我们来看看
js 代码解读复制代码console.log(bus instanceof Object);
可以看到bus
也是属于Object
的,那我们可以知道instanceof
可以判断值的类型,而且是通过原型链来判断的,不懂原型链的小伙伴可以先看看这篇文章(juejin.cn/post/743932…)
手写instanceof
js 代码解读复制代码function myinstanceof(L,R){
while(L!=null){
L = L.__proto__
if(L===R.prototype){
return true;
}
}
return false;
}
我们打造一个函数myinstanceof
,然后我们传入对象L
和构造函数,接着我们来进行判断,如果对象的隐式原型等于构造函数的显示原型,那么就返回true
,不相等则进行循环,L
为构造函数Object
的隐式原型,Object
的隐式原型没有东西,因此当为bull
的时候,循环结束,返回false
让我们来使用一下
js 代码解读复制代码function myinstanceof(L,R){
while(L!=null){
L = L.__proto__
if(L===R.prototype){
return true;
}
}
return false;
}
console.log(myinstanceof([],Array));
console.log(myinstanceof({},Array));
console.log(myinstanceof({},Object));
可以看到,能够成功判断出值的类型
我们知道是通过原型链进行判断的,那么我们就能知道为什么instanceof
不能判断原始类型了,因为原始类型不具备属性和方法,没有隐式原型。
用typeof
只能判断原始类型,用instanceof
又只能判断引用类型,那有没有一种方法可以同时判断原始类型和引用类型呢,确实有
Object.pritotype.toString.call(x)
这个方法就是拿Object
身上的原型上的toString
出来用,call
的作用是将toString
上的this
指向x
并调用toString
,其实就是把toString
借给了x
用,如果不了解,可以看看这篇文章里的介绍
(juejin.cn/post/744007…)
然后让我们看看能否达到我们想使用的效果
js 代码解读复制代码let a = 1
let b = {}
let c = function () {
}
console.log(Object.prototype.toString.call(a));
console.log(Object.prototype.toString.call(b));
console.log(Object.prototype.toString.call(c));
可以看到,它成功判断出来引用类型和原始类型,但是为什么用toString
方法会把它们转换成这么奇怪的样子呢,一个中括号里面放个Object
和数据类型
这我们就要来看看官方文档了
这个文档表示的是当 Object.pritotype.toString.call()
被执行的时候会干的几部操作,如果是undefined
的话,那就直接返回[object Undefined]
,如果是null,那就返回[object Null]
。
其它的,设0为调用To0bject
的结果,将this 值作为参数传递ToObject(this)
设class
为0的[[Class]]
内部属性的值。[[Class]]
是js内部的属性,只有v8能用,可以直接读取变量的类型,最后返回由“[object ”、class 和 “]
” 三块拼接的结果
所以Object.prototype.toString.call(x)
借助Object
原型上的toString
方法在执行过程中会读取 x
的内部属性[[calss]]
这一机制
,还有一个专门判断数组的方法-Array.isArray()
,也是用了[[calss]]
这一机制,因为写死了,没有什么道理可讲,我们知道就好了
总结
在JavaScript
中,类型判断是确保数据按预期处理的关键。typeof
运算符能准确判断除null
外的所有原始类型,但对引用类型(除function
)的判断不够精确。instanceof
通过原型链判断引用类型,却无法处理原始类型。为了同时判断原始类型和引用类型,可以使用Object.prototype.toString.call()
方法,它借助内部属性[[Class]]
返回准确的类型标签。此外,Array.isArray()
是专门用于判断数组的方法,也利用了这一机制。掌握这些类型判断方法,能让你的JavaScript
代码更加健壮和高效。
评论记录:
回复评论: