JS中的类型判断你真的知道吗?

前言

JavaScript是一门动态类型的编程语言,这意味着变量的类型可以在运行时改变。在处理复杂的应用程序时,了解和正确使用类型判断是至关重要的。本文将深入探讨JavaScript中的类型判断,讨论常见的方法、最佳实践以及避免一些常见陷阱的技巧。

在讲解类型判断之前,我们就必须要去了解JavaScript中有哪些数据类型,[在我之前的文章中](JS:给原始类型数据加属性和方法,为什么不报错? - 掘金 (juejin.cn)),曾详细介绍了JS中的两大类数据类型。大家有空可以去看看,之前的文章并没有将类型全部列出,今天顺便在这里补充一下。

1.JavaScript中的数据类型

在开始讨论类型判断之前,我们首先需要了解JavaScript中的数据类型。JavaScript主要分为两大类(七种)数据类型:

  1. 基本数据类型(Primitive Types):

    • undefined
    • null
    • boolean
    • number
    • string
    • symbol
  2. 引用数据类型(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)。

  • 原始值: 包括 undefinednull、布尔值、数字和字符串。这些值是直接存储在变量对象中的,因此可以直接访问。
  • 引用值: 包括对象、数组和函数等。这些值存储的是对象的引用,而不是实际的数据。引用值存储在堆内存中,而变量对象中存储的是指向堆内存中实际数据的指针。

由于历史原因,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 

拓展:

下面直接展示代码:

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的结合

  • 在实际开发中,我们通常会结合使用typeofObject.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

  • 在进行类型判断时,要先判断是否为nullundefined,然后再进行其他类型的判断。

结论

JavaScript类型判断是编写健壮代码的重要组成部分。通过了解各种类型判断方法,结合使用它们,我们可以更准确地判断变量的类型,从而提高代码的可读性和可维护性。在实际项目中,根据情况选择合适的类型判断方法,并时刻注意避免常见的陷阱,将有助于提高代码质量。

留言

如果喜欢博主的文章,还请麻烦给点个小赞♥(ˆ◡ˆԅ),如有说的不对的地方,欢迎及时指正哦

相关推荐
阿伟来咯~1 分钟前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端6 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱9 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai18 分钟前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨19 分钟前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
独行soc1 小时前
#渗透测试#SRC漏洞挖掘#深入挖掘XSS漏洞02之测试流程
web安全·面试·渗透测试·xss·漏洞挖掘·1024程序员节
王哲晓2 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4112 小时前
无网络安装ionic和运行
前端·npm
理想不理想v2 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试