前言
当我们在编写JavaScript代码时,了解和正确使用类型判断是非常重要的。JavaScript是一种弱类型语言,变量的类型可以动态改变,因此在处理数据时,我们经常需要进行类型判断以确保代码的正确性和可靠性。
本文将带领读者从基础到高级,深入剖析JavaScript中的类型判断机制,揭开这一重要主题的面纱。
数据类型
JavaScript有七种原始数据类型与四种引用类型,原始数据类型分别是Undefined、Null、Boolean、Number、String、Symbol和BigInt,引用类型分别是对象、数组、函数、日期。
1. typeof
在进行类型判断时,我们可以使用typeof
操作符来获取变量的类型。
原始数据类型
js
let str = 'hello';
console.log(typeof str); // "string"
let num = 123;
console.log(typeof num); // "number"
let flag = true;
console.log(typeof flag); // "boolean"
let und = undefined;
console.log(typeof und); // "undefined"
let nu = null;
console.log(typeof nu); // "object"
let big = 123n;
console.log(typeof big); // "bigint"
let s = Symbol('hello');
console.log(typeof s); // "symbol"
引用类型
js
let obj = {};
console.log(typeof obj); // "object"
let arr = [];
console.log(typeof arr); // "object"
let fn = function(){};
console.log(typeof fn); // "function"
let date = new Date();
console.log(typeof date); // "object"
我们发现typeof null
返回的是object
,这是一个历史遗留问题,与语言本身的设计和演变有关。在 JavaScript 的早期版本中,变量的值是由存储在变量存储空间中的标记位来表示的。在 JavaScript 中,所有的对象都表示为32位的字(words),而其中的第一个位被用作类型标签。
- 对象类型的类型标签是
000
。null
被认为是一个空对象指针,因此它的类型标签也是000
。
因此,typeof null
返回 "object"
是因为在检查变量类型时,JavaScript 会读取存储在变量存储空间中的类型标签,而 null
的类型标签被解释为对象类型。
虽然这个行为是历史遗留问题,但为了保持向后兼容性,JavaScript 的设计者选择保留了这个特性。在现代的 JavaScript 中,为了准确判断变量是否为 null
,推荐使用严格相等运算符 ===
:
js
console.log(nu === null) //true
除此之外,我们发现引用类型只能将函数判断为function
、将对象判断为object
,而数组跟函数也判断为object
。所以我们还需要再找一个能进一步判断引用类型的操作符。
2. instanceof
instanceof
操作符用于检查对象是否是特定类(构造函数)的实例。它通过检查对象的原型链来确定对象的类型。如果对象是指定类的实例,则返回 true
,否则返回 false
。
js
let obj = {}
console.log(obj instanceof Object); // true
let arr = []
console.log(arr instanceof Array); // true
let fn = function(){}
console.log(fn instanceof Function); // true
let date = new Date()
console.log(date instanceof Date); // true
所以我们可以通过instanceof
,再结合构造函数来判断引用类型。
于是我们可以手写一个instanceof
:
js
function instanceOF(L, R) {
let left = L.__proto__; // 初始化变量 left 为实例对象 L 的隐式原型
let right = R.prototype; // 初始化变量 right 为构造函数 R 的显示原型
while (left !== null) { // 迭代访问左操作数的原型链,如果不为空则进循环
if (left === right) { // 检查当前对象的隐式原型是否与构造函数的显示原型相等
return true; // 如果相等,返回 true,表示这个实例对象是这个构造函数创建的
}
left = left.__proto__; // 移动到链中的下一个隐式原型
}
return false; // 如果没有找到匹配,返回 false
}
//举例:
console.log(instanceOF([],Array));//true
但是我们在运用instanceof
的时候,还会出现一种情况:
js
let arr = []
console.log(arr instanceof Object); // true
我们发现,数组也可以被判定为对象,所以当我们要判断一个数据类型是不是对象的时候,用instanceof
就不妥,因为数组可以被识别成对象。导致我们判断错误。
那有没有能够直接判断类型的方法?
3. Object.prototype.toString()
官方定义: Object.prototype.toString()
当调用toString
方法时,将执行以下步骤:
- 如果
this
值未定义,则返回"[object undefined]"
。- 如果
this
值为空,则返回"[object null]"
。- 让
o
作为传递this
值作为参数的object
调用的结果。- 设
class
为o
的内部属性[[Class]]
的值。- 返回三个字符串
"[object "
和class
和"]"
连接后的String
值。
以上为官方规定,在这里就不过多解释,我们直接用就行了。(参考原文Annotated ES5)
js
let number = 42;
console.log(Object.prototype.toString.call(number)); // "[object Number]"
let str = "Hello";
console.log(Object.prototype.toString.call(str)); // "[object String]"
let bool = true;
console.log(Object.prototype.toString.call(bool)); // "[object Boolean]"
console.log(Object.prototype.toString.call(null));//'[object Null]'
console.log(Object.prototype.toString.call(undefined));//'[object Undefined]'
let bigint = 123n
console.log(Object.prototype.toString.call(bigint));//'[object BigInt]'
let symbol = Symbol('hello')
console.log(Object.prototype.toString.call(symbol));//'[object Symbol]'
let array = [];
console.log(Object.prototype.toString.call(array)); // "[object Array]"
let date = new Date();
console.log(Object.prototype.toString.call(date)); // "[object Date]"
var obj = {};
console.log(Object.prototype.toString.call(obj));//'[object Object]'
let func = function() {};
console.log(Object.prototype.toString.call(func)); // "[object Function]"
我们可以用这个方法判断然后数据类型。在这里我们通过使用 call
方法,可以将 this
设置为任何我们想要检查的对象,从而获取该对象的准确类型信息。
我们可以稍加改进,让这个方法更容易为我们所用:
js
var s ='thisisstring'
function isType(s) {
return Object.prototype.toString.call(s).slice(8,-1)
}
if(isType === 'String'){
//xxx
}
通过isType
函数,我们就可以获取变量 s
的类型,并与字符串 'String'
进行比较,其中slice(8,-1)
用于截取类型字符串,去除 "[object "
和 "]"
部分。
最后
通过本文的学习,我们不仅深入了解了基本的 typeof
操作符和 instanceof
操作符,还探讨了更为精准的 Object.prototype.toString
方法。这些工具不仅帮助我们在编码过程中避免潜在的错误,还为处理各种复杂的数据结构提供了可靠的手段。
我的Gitee: CodeSpace (gitee.com)
技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!