前言
JavaScript是一门动态类型的编程语言,这意味着变量的类型可以在运行时改变。在处理复杂的应用程序时,了解和正确使用类型判断是至关重要的。本文将深入探讨JavaScript中的类型判断,讨论常见的方法、最佳实践以及避免一些常见陷阱的技巧。
在讲解类型判断之前,我们就必须要去了解JavaScript中有哪些数据类型,[在我之前的文章中](JS:给原始类型数据加属性和方法,为什么不报错? - 掘金 (juejin.cn)),曾详细介绍了JS中的两大类数据类型。大家有空可以去看看,之前的文章并没有将类型全部列出,今天顺便在这里补充一下。
1.JavaScript中的数据类型
在开始讨论类型判断之前,我们首先需要了解JavaScript中的数据类型。JavaScript主要分为两大类(七种)数据类型:
-
基本数据类型(Primitive Types):
undefined
null
boolean
number
string
symbol
-
引用数据类型(Reference Types):
-
object
-
Array
-
Function
-
Date
-
等等...
-
如果要对上述数据进行类型判断,你会用什么方法,我知道,你首先想到的肯定是typeof运算符,那我们就先一起去认识一下typeof运算符吧。
2.typeof运算符
JavaScript提供了typeof
运算符,可以用来判断变量的类型。它返回一个表示变量类型的字符串。让我们看一些例子:
js
let a = 10;
let b = 'Hello';
let c = true;
let d = undefined;
let e = Symbol('hello');
console.log(typeof a); // 输出: "number"
console.log(typeof b); // 输出: "string"
console.log(typeof c); // 输出: "boolean"
console.log(typeof d); // 输出: "undefined"
console.log(typeof e); // 输出: "symbol"
你是否注意到,上述typeof的判断里,原始数据类型六个里面占了五个,null我并没有写在上面,因为null是特例。看下述代码:
js
let f = null;
console.log(typeof f); // 输出: "object"
为什么会输出object?
在JavaScript早期的实现中,typeof null
的结果确实是"object",这是一个已知的历史遗留问题。这是因为在JavaScript的设计中,null
被视为一个空的对象指针。为什么不修改这一问题呢?因为如果现在对null进行修改的话,市面上几乎所有程序都得重新书写,所以这种行为在 ECMAScript 的规范中被保留下来,以确保对现有代码的向后兼容性
typeof能判断引用数据类型吗?
- 看下面案例:
js
let obj = {};
let arr = [1, 2, 3];
let date = new Date();
let fuc = function(){};
console.log(typeof obj); // 输出: "object"
console.log(typeof arr); // 输出: "object"
console.log(typeof date); // 输出: "object"
console.log(typeof fuc); // 输出: "function"
为什么前面三个输出object,而function却是对的呢?
在 JavaScript 的早期版本中,变量的存储方式有两种:原始值(Primitive Values)和引用值(Reference Values)。
- 原始值: 包括
undefined
、null
、布尔值、数字和字符串。这些值是直接存储在变量对象中的,因此可以直接访问。- 引用值: 包括对象、数组和函数等。这些值存储的是对象的引用,而不是实际的数据。引用值存储在堆内存中,而变量对象中存储的是指向堆内存中实际数据的指针。
由于历史原因,
typeof
在设计时被限制为返回一组有限的字符串,表示基本数据类型。在这个设计中,除了函数以外的引用类型都被归类为 "object"。
看起来typeof并不够满足我们的日常需求,下面介绍另一种进行类型判断的运算符。
3.instanceof运算符
instanceof
运算符用于检查对象是否是某个特定类型的实例。它只适用于引用类型的判断,例如:
js
let arr = [1, 2, 3];
let func = function() {};
let n = 123 ;
let m = null;
console.log(arr instanceof Array); // 输出: true
console.log(func instanceof Function); // 输出: true
console.log(n instanceof Number); // 输出: false
console.log(m instanceof Object); // 输出: false
拓展:
-
你能手搓一个instanceof的实现原理代码吗?
-
原理是原型链,[我在之前的文章](解析JavaScript原型(二): GPT看见也懵的原型链 - 掘金 (juejin.cn))曾重点介绍过原型链,有不理解的可以去看看。
下面直接展示代码:
js
function myInstanceof(L,R){
while(L !== null){
if(L.__proto__ === R.prototype){
return true;
}else{
L = L.__proto__;
}
}
return false;
}
const arr = [1]
console.log(myInstanceof(arr,Array)) // 输出:true
console.log(myInstanceof(arr,Object)) // 输出:true
上述两种方法似乎都存在弊端,并不能实现所有数据类型的判断,那么JavaScript中是否存在可以同时判断所有数据的类型的方法呢?答案是肯定的,这也就是我下面要讲的。
4.Objetc.prototype.toString方法
- 为了同时判断所有类型,我们可以使用
Object.prototype.toString
方法。这个方法返回一个表示对象的字符串,其中包含对象的类型信息。但得结合call()方法和slice()方法来实现。如下:
js
let n = 123;
let str = 'hello';
let arr = [1, 2, 3];
let func = function() {};
console.log(Object.prototype.toString.call(n)); // 输出: "[object Number]"
console.log(Object.prototype.toString.call(str)); // 输出: "[object String]"
console.log(Object.prototype.toString.call(arr)); // 输出: "[object Array]"
console.log(Object.prototype.toString.call(func)); // 输出: "[object Function]"
// 通过字符串截取,可以返回指定类型,如下:
console.log(Object.prototype.toString.call(n).slice(8, -1)); // 输出: "Number"
console.log(Object.prototype.toString.call(arr).slice(8, -1)); // 输出: "Array"
5. 使用typeof和Object.prototype.toString的结合
- 在实际开发中,我们通常会结合使用
typeof
和Object.prototype.toString
以得到更全面的类型判断。下面是一个例子:
js
function getType(value) {
const type = typeof value;
if (type !== 'object') {
return type;
}
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
let x = 10;
let y = 'Hello';
let z = [1, 2, 3];
console.log(getType(x)); // 输出: "number"
console.log(getType(y)); // 输出: "string"
console.log(getType(z)); // 输出: "array"
这样的封装使得我们可以更方便地获取变量的类型,并且能够正确地处理引用类型。
特别提醒:
6. 避免类型判断的陷阱
- 在进行类型判断时,有一些常见的陷阱需要注意。以下是一些避免这些陷阱的最佳实践:
6.1. 避免使用==
进行比较
- 使用
==
进行比较时,JavaScript会进行类型转换,可能导致意外的结果。建议使用===
进行严格比较,不仅比较值还比较类型。
js
let num = 10;
let strNum = '10';
console.log(num == strNum); // 输出: true
console.log(num === strNum); // 输出: false
6.2. 谨慎处理NaN
- 使用
isNaN
函数来判断一个值是否为NaN,而不是直接进行等值比较。
6.3. 小心处理null和undefined
- 在进行类型判断时,要先判断是否为
null
或undefined
,然后再进行其他类型的判断。
结论
JavaScript类型判断是编写健壮代码的重要组成部分。通过了解各种类型判断方法,结合使用它们,我们可以更准确地判断变量的类型,从而提高代码的可读性和可维护性。在实际项目中,根据情况选择合适的类型判断方法,并时刻注意避免常见的陷阱,将有助于提高代码质量。
留言
如果喜欢博主的文章,还请麻烦给点个小赞♥(ˆ◡ˆԅ),如有说的不对的地方,欢迎及时指正哦