【前端】理解 JavaScript 中 typeof 操作符的独特行为

news2025/1/23 3:09:07

在这里插入图片描述

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
本文专栏: 前端

文章目录

  • 💯前言
  • 💯`typeof` 操作符的基本使用
  • 💯为什么 `typeof` 数组是 "object"?
  • 💯为什么 `typeof {}` 返回 "object"?
  • 💯为什么 `typeof null` 也是 "object"?
  • 💯`typeof null` 返回 "object" 的历史原因
  • 💯其它 `typeof` 的怪异行为
  • 💯更好的类型判断方式
  • 💯最佳实践与建议
  • 💯小结


在这里插入图片描述


💯前言

  • JavaScript 是一种灵活且动态的编程语言,其设计中包含了诸多独特之处。这些特性为开发者提供了极大的自由度,但也伴随着某些复杂性,尤其是在类型系统的处理上。typeof 操作符便是其中一个常见的例子,它的表现往往让新手乃至经验丰富的开发者感到困惑。在本文中,我们将系统性地探讨typeof操作符的行为,特别是在处理数组对象null时的表现,并揭示这些行为背后的深层原因,以及如何在实践中应对这些情况。为了全面理解这些问题,我们将深入分析这些类型的历史背景,并提供实践中可以应用的一些实用技巧
    JavaScript在这里插入图片描述


💯typeof 操作符的基本使用

在这里插入图片描述
在 JavaScript 中,typeof 是一个用于检测变量类型的操作符。它返回一个字符串,表示变量的数据类型。最常见的类型包括:

  • "number"
  • "string"
  • "boolean"
  • "object"
  • "undefined"
  • "function"

在日常开发过程中,typeof 操作符通常是一个非常方便的工具,用于快速判断变量的类型。然而,JavaScript 中的一些类型判断行为可能会让人感到困惑,特别是在涉及数组、普通对象以及 null 的时候。这种困惑源于 JavaScript 语言设计中的某些妥协和历史遗留问题,它们塑造了当前语言中某些行为的独特性和不一致性。


💯为什么 typeof 数组是 “object”?

首先让我们来讨论一个很常见的例子,即对数组的类型判断:

let arr = [1, 2, 3];
console.log(typeof arr); // 输出 "object"

在这里插入图片描述

在 JavaScript 中,数组实际上是对象的一种特殊类型。虽然数组和普通对象有显著的不同,例如数组具有 length 属性,提供了诸如 pushpop 等特殊的方法,并且其结构通常是有序的,但在底层,JavaScript 实现数组时仍将其视为对象。因此,typeof 操作符会返回 "object",这可能与直觉不符。

为了更加精确地判断一个变量是否是数组,我们可以使用 Array.isArray() 方法:

console.log(Array.isArray(arr)); // 输出 true

在这里插入图片描述

Array.isArray() 是判断数组的最佳方式,因为它能够准确地辨别一个值是否为数组,而不依赖于 typeof 的笼统返回值。之所以设计这个方法,是因为开发者通常希望将数组与普通对象区别开来,而 typeof 由于其固有的局限性无法做到这一点。


💯为什么 typeof {} 返回 “object”?

普通对象是 JavaScript 中的基本构造块之一。它们通过字面量 {} 来创建,可以用来存储键值对:

let obj = {};
console.log(typeof obj); // 输出 "object"

在这里插入图片描述

对于字面量 {}typeof 返回 "object" 是符合直觉的,因为 {} 代表的是 JavaScript 中典型的对象类型。对象是 JavaScript 中的一种复合数据类型,其主要功能是表示键值对的集合,且允许动态地添加或移除属性。理解对象在 JavaScript 中的表现形式以及如何被 typeof 识别,对掌握这一语言至关重要,尤其是对象几乎参与了所有复杂数据结构的构建。


💯为什么 typeof null 也是 “object”?

接下来,我们来讨论一个颇具迷惑性的问题:

console.log(typeof null); // 输出 "object"

在这里插入图片描述

null 表示的是“空值”或“空引用”,通常用于指示某个对象或值为空。在绝大多数编程语言中,我们可能期望 null 是一种单独的数据类型。然而,在 JavaScript 中,typeof null 返回 "object",这显然不符合直觉,也让开发者在编写代码时容易出现困惑。


💯typeof null 返回 “object” 的历史原因

typeof null 返回 "object" 是 JavaScript 语言中的一个历史遗留问题。这种行为可以追溯到 JavaScript 最早的实现。在初期的实现中,JavaScript 采用了一种称为标签存储的方式来表示不同的数据类型。对象的标签值为 0,而 null 被视为对象的一个特殊标志,也因此被分配了与对象相同的标签值。这一实现细节导致了 typeof null 返回 "object" 的现象。

尽管这一实现方式在现代 JavaScript 中已经显得过时且不合逻辑,但由于语言的向后兼容性,无法对其进行根本性的更改,因为这种变动可能会导致大量现存代码失效。因此,这个问题一直被保留下来,成为开发者在使用 JavaScript 时必须了解的一个特性
为了避免这种困惑,开发者在判断一个值是否为 null 时,通常使用严格的相等比较运算符:

let value = null;
console.log(value === null); // 输出 true

在这里插入图片描述

通过这种方式,可以确保 valuenull,而不会被误判为其他类型的对象。这种做法不仅直观,而且可以减少由于误判类型带来的潜在错误,尤其是在需要处理复杂对象和空引用时显得尤为重要。


💯其它 typeof 的怪异行为

JavaScript 中的 typeof 操作符还存在一些其他特殊情况。例如,当 typeof 用于函数时,它会返回 "function",这一点相对合理,因为函数在 JavaScript 中是一等公民,既可以作为变量被赋值,也可以作为参数传递给其他函数,甚至可以作为返回值。

function example() {}
console.log(typeof example); // 输出 "function"

在这里插入图片描述

虽然函数在底层也是对象的一种特殊类型,但 typeof 将它们单独识别为 "function",使得它们与普通对象区分开来,从而为开发者提供了一种快速判断的方式。

另一方面,typeof undefined 返回 "undefined",这相对简单直观。它表示一个变量尚未被赋值,这种行为在变量初始化和检查时非常有用,能够快速地判断某个变量是否处于未定义状态。


💯更好的类型判断方式

由于 typeof 存在一些不直观的行为,因此在复杂应用中,我们需要更加可靠的方式来进行类型判断。以下是一些常用的类型判断方式:

  1. Array.isArray() 用于数组

    • Array.isArray(value) 是判断数组的最佳方式,因为它专门用于判断数组,无论数据结构多复杂都能准确识别。
  2. instanceof 操作符

    • instanceof 可以用来判断某个值是否是某个构造函数的实例。这种方法适用于多种不同类型的数据结构,尤其是在涉及自定义类和继承时。
    console.log([] instanceof Array); // 输出 true
    console.log({} instanceof Object); // 输出 true
    

    在这里插入图片描述

  3. Object.prototype.toString.call()

    • Object.prototype.toString.call(value) 是一种非常强大的类型判断方法,能够精确返回值的类型信息:
    console.log(Object.prototype.toString.call([])); // 输出 "[object Array]"
    console.log(Object.prototype.toString.call({})); // 输出 "[object Object]"
    console.log(Object.prototype.toString.call(null)); // 输出 "[object Null]"
    

    在这里插入图片描述

    这种方式能够提供更加详细的类型信息,尤其是在处理复杂和不确定的数据时非常有用。它被视为所有类型判断方法中最通用的方式,特别适合于需要对输入进行全面验证的应用场景。


💯最佳实践与建议

  1. 避免直接用 typeof 判断数组和 null

    • 对于数组,应使用 Array.isArray() 进行判断。
    • 对于 null,直接使用 === null 进行判断。
  2. 理解并适应历史遗留问题

    • 理解 JavaScript 中 typeof 的行为历史原因,有助于避免编码中的常见陷阱。了解 typeof null 返回 "object" 是一个历史遗留问题,可以帮助你更快地在调试过程中发现问题。
  3. 结合使用多种类型判断方式

    • 在复杂应用中,单靠 typeof 通常不足以满足所有需求。结合使用 instanceofObject.prototype.toString.call() 等方法,可以实现更加精确和可靠的类型判断。这些方法在大型应用程序中尤为重要,特别是在处理多样化的数据时。
  4. 团队开发中的一致性

    • 在团队开发中,保持类型检查方法的一致性非常重要。例如,统一使用 Object.prototype.toString.call() 作为标准类型检查方式,可以确保所有团队成员编写的代码在风格和行为上保持一致,从而减少不必要的错误和维护成本。

在这里插入图片描述


💯小结

  • 在这里插入图片描述
    JavaScript 是一种极为灵活的语言,其设计之初为了实现简便易用做出了许多权衡,但也因此引入了一些复杂性,特别是在类型系统上。其中,typeof 操作符的行为便是一个经典的例子。通过深入理解typeof在不同场景下的表现以及其背后的历史原因,开发者可以有效避免一些常见的陷阱,并编写出更加健壮和可靠的代码。
    尽管 JavaScript 的某些设计决策显得不那么严谨,但其灵活性广泛的生态系统使得它在现代 Web 应用开发中占据了重要地位。理解并掌握这些细微的特性不仅能够帮助开发者编写更具稳定性的代码,还能在调试和代码审查过程中显著提高效率

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2252421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一键解析RAW文件,GPS定位展示,摄影师专用照片管理软件

作为一款精心打造的数码影像管理工具,bkViewer以其轻量化设计和强大的功能特性脱颖而出。这款软件不仅能够完美处理各类主流图片格式,更整合了专业级的图像信息处理系统,包含完整的EXIF、XMP、IPTC、GPS、ICC等元数据解析能力,并通…

import.meta.glob动态加载图片

import.meta.glob 基于Vite(Vue 3 默认构建工具),用于动态导入模块,特别是当你需要批量导入文件或模块时. const modules import.meta.glob(/path/to/files/**/*.js);注意:import.meta.glob 是针对 源代码&#xff…

[高阶数据结构六]最短路径算法

1.前言 最短路径算法是在图论的基础上讲解的,如果你还不知道图论的相关知识的话,可以阅读下面几篇文章。 [高阶数据结构四] 初始图论_初始图结构-CSDN博客 [高阶数据结构五] 图的遍历和最小生成树_图的遍历和生成树求解-CSDN博客 本章重点:…

开源的跨平台SQL 编辑器Beekeeper Studio

一款开源的跨平台 SQL 编辑器,提供 SQL 语法高亮、自动补全、数据表内容筛选与过滤、连接 Web 数据库、存储历史查询记录等功能。该编辑器支持 SQLite、MySQL、MariaDB、Postgres 等主流数据库,并兼容 Windows、macOS、Linux 等桌面操作系统。 项目地址…

mysql 5.7安装及安装后无法启动问题处理

下载安装包,直接解压 配置环境变量 创建my.ini文件 [mysqld] #端口号 port 3306 #mysql-5.7.27-winx64的路径 basedirD:/soft/mysql57 #mysql-5.7.27-winx64的路径\data datadirD:/soft/mysql57/data #最大连接数 max_connections200 #编码 character-set-server…

spine 动画层 动态权重

前奏.业务背景 这边想实现一个功能,项目中有 一只猫 猫的头会盯着逗猫棒移动。因为素材还没到所以这里使用了 spine 自带的猫头鹰。他的动画 刚好挺有针对性:(关联上篇)https://blog.csdn.net/nicepainkiller/article/details/144…

Spark 内存管理机制

Spark 内存管理 堆内内存和堆外内存 作为一个 JVM 进程,Executor 的内存管理建立在 JVM(最小为六十四分之一,最大为四分之一)的内存管理之上,此外spark还引入了堆外内存(不在JVM中的内存),在spark中是指不…

Vision Transformer(vit)的主干

图解: 代码: class VisionTransformer(nn.Module):def __init__(self, img_size224, patch_size16, in_c3, num_classes1000,embed_dim768, depth12, num_heads12, mlp_ratio4.0, qkv_biasTrue,qk_scaleNone, representation_sizeNone, distilledFalse,…

mongodb配置ssl连接

mongodb5.0.9 centos7.6x86 1、正常启动mongod -f mongodb.conf 2、生成所需要的ssl证书 服务端ssl配置: 2.1生成ca.pem证书 #-x509: 用于生成自签证书,如果不是自签证书则不需要此项 #-days: 证书的有效期限&…

Linux 中的 ls 命令:从使用到源码解析

ls 命令是 Linux 系统中最常用和最基本的命令之一。下面将深入探讨 ls 命令的使用方法、工作原理、源码解析以及实际应用场景。 1. ls 命令的使用** ls 命令用于列出目录内容,显示文件和目录的详细信息。 1.1 基本用法 ls [选项] [文件或目录]例如: …

Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo)

Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo) 目录 Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo) 一、简单介绍 二、PyTorch 三、CNN 1、神经网络 2、卷…

【C语言】结构体(二)

一&#xff0c;结构体的初始化 和其它类型变量一样&#xff0c;对结构体变量可以在定义时指定初始值 #include <stdio.h> #include <stdlib.h> struct books // 结构体类型 {char title[50];char author[50]; //结构体成员char subject[100];int book_id; }…

C++(4个类型转换)

1. C语言中的类型转换 1. 隐式 类型转换&#xff1a; 具有相近的类型才能进行互相转换&#xff0c;如&#xff1a;int,char,double都表示数值。 2. 强制类型转换&#xff1a;能隐式类型转换就能强制类型转换&#xff0c;隐式类型之间的转换类型强相关&#xff0c;强制类型转换…

Windows下从命令行(Powershell/CMD)发送内容到系统通知中心

Windows下从命令行&#xff08;Powershell/CMD&#xff09;发送内容到系统通知中心 01 前言 在平时写脚本的时候&#xff0c;将日志等信息直接输出到控制台固然是最直接的&#xff0c;而如果是一些后台执行的任务&#xff0c;不需要时刻关注运行细节但是又想知道一些大致的情…

四、初识C语言(4)

一、作业&#xff1a;static修饰局部变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> //作业&#xff1a;static修饰局部变量 int sum (int a) {int c 0;static int b 3;c 1;b 2;return (abc); } int main() {int i 0;int a …

基于深度学习的甲状腺结节影像自动化诊断系统(PyQt5界面+数据集+训练代码)

随着医学影像技术的发展&#xff0c;计算机辅助诊断在甲状腺结节的早期筛查中发挥着重要作用。甲状腺结节的良恶性鉴别对临床治疗具有重要意义&#xff0c;但传统的诊断方法依赖于医生的经验和影像学特征&#xff0c;存在一定的主观性和局限性。为了解决这一问题&#xff0c;本…

VLC 播放的音视频数据处理流水线搭建

VLC 播放的音视频数据处理流水线搭建 音视频流播放处理循环音频输出处理流水线VLC 用 input_thread_t 对象直接或间接管理音视频播放有关的各种资源,包括 Access, Demux, Decode, Output, Filter 等,这个类型定义 (位于 vlc-3.0.16/include/vlc_input.h) 如下: s…

Android 12系统源码_RRO机制(一)Runtime Resource Overlay机制实践

前言 Android的RRO&#xff08;Runtime Resource Overlay&#xff09;机制允许开发者在运行时替换或重写系统资源&#xff0c;例如布局、图标、字符串等。这个机制的目标是为了支持设备定制和主题化&#xff0c;特别是在不修改系统源代码的情况下。RRO通过在系统的资源上叠加一…

Tomcat新手成长之路:安装部署优化全解析(下)

接上篇《Tomcat新手成长之路&#xff1a;安装部署优化全解析&#xff08;上&#xff09;》: link 文章目录 7.应用部署7.1.上下文7.2.启动时进行部署7.3.动态应用部署 8.Tomcat 类加载机制8.1.简介8.2.类加载器定义8.3.XML解析器和 Java 9.JMS监控9.1.简介9.2.启用 JMX 远程监…

动态代理如何加强安全性

在当今这个信息爆炸、网络无孔不入的时代&#xff0c;我们的每一次点击、每一次浏览都可能留下痕迹&#xff0c;成为潜在的安全隐患。如何在享受网络便利的同时&#xff0c;有效保护自己的隐私和信息安全&#xff0c;成为了每位网络使用者必须面对的重要课题。动态代理服务器&a…