类型检测
前言:
js的类型检测是老生常谈的一个点,那为什么还要写这篇文章呢?
这个点不管在面试还是知识储备都是要会的。
所以这篇文章算是自己的一个记录,如果顺便能对你有点帮助的话,那我感到很荣幸!!!!
嘻嘻嘻嘻嘻,有不对的地方请都多指教,作出修改
进入正题
typeof
(返回值是字符串类型哦,连用 typeof typeof 111 ==> string )
对外称:只能检测基本数据类型。
是这样没错,但是往往别人问了,不只是要你这个回答。
先让我们 look look,基本返回的值。
类型 | 结果 |
---|---|
Undefined | "undefined" |
Null | "object" (原因) |
Boolean | "boolean" |
Number | "number" |
BigInt | "bigint" |
String | "string" |
Symbol | "symbol" |
Function(在 ECMA-262 中实现 [[Call]];classes也是函数) | "function" |
其他任何对象 | "object" |
上面的链接点击会跳转 MDN,有小伙伴需要更加详细的解释,或者知道其他的信息,可以点击跳转
那我就先说说我的:
-
有一个例外是检测基本类型null的时候,返回的不是预计的代表null类型的字符串,
而是object。
在JS的最初版本中使用的是32位系统,为了性能考虑使用低位存储变量的类型信息,
000开头的是对象,null是全0,所以将null误判为Object了。
虽然现在的内部类型判断代码已经改变了,但bug永久的遗留下来了。
-
typeof判断对象,除了function都会显示object,所以typeof并不能准确地判断变量类型.
-
局限性以及一些例外
- 数组和 null :
typeof
对于数组会返回"object"
,而不是"array"
;对于null
也会返回"object"
,这是 JavaScript 语言本身的历史遗留问题。 - 对象内部的具体类型 :
typeof
无法区分对象内部的具体类型,它会将所有对象的内部类型都归为"object"
。 - NaN 检测 :
typeof NaN
会返回"number"
,这是因为NaN
是一种特殊的数值。 - 函数内部的具体类型 :
typeof
无法区分不同类型的函数,它会将所有函数都归为"function"
。 - 无法检测引用类型的具体类型 :
typeof
无法检测出引用类型(对象、数组、函数等)的具体类型,比如无法区分一个对象是普通对象还是数组对象。 - 举个例子,假设我们有一个变量
arr
,它存储着一个数组对象:
ini
var arr = [1, 2, 3];
如果我们使用 typeof
对 arr
进行检测:
javascript
console.log(typeof arr); // 输出 "object"
同样地,对于普通的对象也是一样的情况:
ini
var obj = { name: "John", age: 25 };
console.log(typeof obj); // 输出 "object"
这意味着当我们使用 typeof
操作符来检测引用类型时,无法得知它们具体属于哪种引用类型。这就是说,typeof
无法提供关于对象、数组、函数等引用类型的具体细分信息。
为了更准确地识别引用类型的具体类型,我们可以使用更为详细的方法,比如:
- 使用
Array.isArray()
方法来检测一个对象是否为数组。 - 使用
Object.prototype.toString.call()
方法来获取对象的精确类型信息。
instanceof
上面不是说了typeof,那接下来就是他的好兄弟 instanceof。
instanceof
运算符的原理是基于对象的原型链进行检查。它用于确定一个对象是否属于特定类型或该类型的子类。
当使用 instanceof
运算符时,它会检查对象的原型链上是否存在该类型的原型。如果存在,则返回 true
,否则返回 false
。
下面是 instanceof
运算符的工作原理的一般步骤:
- 检查对象的原型链中的每个原型是否与指定的构造函数的原型相等。
- 如果在原型链中找到匹配的原型,返回
true
。 - 如果在整个原型链上都没有找到匹配的原型,返回
false
。
让我们通过一个示例来说明原理:
javascript
javascriptCopy Code
function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
var myDog = new Dog();
console.log(myDog instanceof Dog); // 输出 true
console.log(myDog instanceof Animal); // 输出 true
在这个例子中,我们创建了两个构造函数 Animal
和 Dog
。然后,我们将 Dog
的原型设置为 Animal
的实例,这样 Dog
继承了 Animal
的属性和方法。
接着,我们使用 new
关键字创建了一个 myDog
对象,它是 Dog
类型的实例。
最后,我们使用 instanceof
运算符检查 myDog
是否是 Dog
类型的实例,以及是否是 Animal
类型的实例。由于 Dog
的原型链中存在 Animal
的原型,所以两个检查都返回了 true
。
需要注意的是:
instanceof
运算符不会检查对象的构造函数,而是检查构造函数的原型。- 如果
constructor
属性被重写或更改,instanceof
可能会给出错误的结果。
总结起来,instanceof
运算符通过检查对象的原型链确定对象是否属于指定类型或其子类。它是基于原型继承机制的一种类型判断方法。
两者都可以检测的(object.prototype.tostring.call())
1.我相信大多数人对这个方法有一个误区。
包括我,在刚开始学JS的时候,容易对这个方法产生了一个错误的认知。
比如 const a = {name:"韩振方"},
好像觉得 a.toString
方法应该返回字符串类型的{name:"韩振方"}
。
问题的关键点就恰恰在这个地方。
2.首先我们要知道 toString
这个方法,这个函数的返回值本来就应该是下面的固定格式。
一个字符串个格式的 [object xxxx]xxxx
代表着调用这个方法的"数据"的数据类型。
3.重点来了:
js其实是重写了某些数据类型的toString方法,所以才会造成下面的情况,在这里我们拿函数类型举例子,其他数据类型同理:
嗯...对,这才是我理想中的toString,会返回这个变量的字符串显示样子。
4.要想搞明白这个知识点,在这里你必须要对原型链和原型有清晰的认识。我们知道,JS的大原型其实是Object构造函数的prototype指向的那个Object,JS的世界的来源就是它。
这个对象上的toString方法才是原汁原味的toString。
5.当我们用delete方法去删除Function.prototype(也就是Function构造函数的原型)身上的toString,然后我们再次调用name.toString会发生什么呢?
6.但是我们往往不会用delete去删除,所以就采用call方法去改变Object.prototype.toString方法this的指向。
结束
这篇文字只是当一个记录作用,如果有错误的可以指教一下我更改。
还有其他检测类型的方法的,现在只是粗略记录,持续更新~~~~~~~