当前位置: 首页 > news >正文

JavaScript专题之类型判断(下)

参考原文:JavaScript专题之类型判断(下)

前言

在上篇《JavaScript专题之类型判断(上)》中,我们抄袭 jQuery 写了一个 type 函数,可以检测出常见的数据类型,然而在开发中还有更加复杂的判断,比如 plainObject、空对象、Window 对象等,这一篇就让我们接着抄袭 jQuery 去看一下这些类型的判断。

plainObject

plainObject 来自于 jQuery,可以翻译成纯粹的对象,所谓"纯粹的对象",就是该对象是通过 “{}” 或 “new Object” 创建的,该对象含有零个或者多个键值对。

之所以要判断是不是 plainObject,是为了跟其他的 JavaScript对象如 null,数组,宿主对象(documents)等作区分,因为这些用 typeof 都会返回object。

jQuery提供了 isPlainObject 方法进行判断,先让我们看看使用的效果:

function Person(name) {this.name = name;
}console.log($.isPlainObject({})) // trueconsole.log($.isPlainObject(new Object)) // trueconsole.log($.isPlainObject(Object.create(null))); // trueconsole.log($.isPlainObject(Object.assign({a: 1}, {b: 2}))); // trueconsole.log($.isPlainObject(new Person('yayu'))); // falseconsole.log($.isPlainObject(Object.create({}))); // false

由此我们可以看到,除了 {} 和 new Object 创建的之外,jQuery 认为一个没有原型的对象也是一个纯粹的对象。

实际上随着 jQuery 版本的提升,isPlainObject 的实现也在变化,我们今天讲的是 3.0 版本下的 isPlainObject,我们直接看源码:

// 上节中写 type 函数时,用来存放 toString 映射结果的对象
var class2type = {};// 相当于 Object.prototype.toString
var toString = class2type.toString;// 相当于 Object.prototype.hasOwnProperty
var hasOwn = class2type.hasOwnProperty;function isPlainObject(obj) {var proto, Ctor;// 排除掉明显不是obj的以及一些宿主对象如Windowif (!obj || toString.call(obj) !== "[object Object]") {return false;}/*** getPrototypeOf es5 方法,获取 obj 的原型* 以 new Object 创建的对象为例的话* obj.__proto__ === Object.prototype*/proto = Object.getPrototypeOf(obj);// 没有原型的对象是纯粹的,Object.create(null) 就在这里返回 trueif (!proto) {return true;}/*** 以下判断通过 new Object 方式创建的对象* 判断 proto 是否有 constructor 属性,如果有就让 Ctor 的值为 proto.constructor* 如果是 Object 函数创建的对象,Ctor 在这里就等于 Object 构造函数*/Ctor = hasOwn.call(proto, "constructor") && proto.constructor;// 在这里判断 Ctor 构造函数是不是 Object 构造函数,用于区分自定义构造函数和 Object 构造函数return typeof Ctor === "function" && hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object);
}

注意:我们判断 Ctor 构造函数是不是 Object 构造函数,用的是 hasOwn.toString.call(Ctor),这个方法可不是 Object.prototype.toString,不信我们在函数里加上下面这两句话:

console.log(hasOwn.toString.call(Ctor)); // function Object() { [native code] }
console.log(Object.prototype.toString.call(Ctor)); // [object Function]

发现返回的值并不一样,这是因为 hasOwn.toString 调用的其实是 Function.prototype.toString,毕竟 hasOwnProperty 可是一个函数!

而且 Function 对象覆盖了从 Object 继承来的 Object.prototype.toString 方法。函数的 toString 方法会返回一个表示函数源代码的字符串。具体来说,包括 function关键字,形参列表,大括号,以及函数体中的内容。

EmptyObject

jQuery提供了 isEmptyObject 方法来判断是否是空对象,代码简单,我们直接看源码:

function isEmptyObject( obj ) {var name;for ( name in obj ) {return false;}return true;
}

其实所谓的 isEmptyObject 就是判断是否有属性,for 循环一旦执行,就说明有属性,有属性就会返回 false。

但是根据这个源码我们可以看出isEmptyObject实际上判断的并不仅仅是空对象。

举个栗子:

console.log(isEmptyObject({})); // true
console.log(isEmptyObject([])); // true
console.log(isEmptyObject(null)); // true
console.log(isEmptyObject(undefined)); // true
console.log(isEmptyObject(1)); // true
console.log(isEmptyObject('')); // true
console.log(isEmptyObject(true)); // true

以上都会返回 true。

但是既然 jQuery 是这样写,可能是因为考虑到实际开发中 isEmptyObject 用来判断 {} 和 {a: 1} 是足够的吧。如果真的是只判断 {},完全可以结合上篇写的 type 函数筛选掉不适合的情况。

Window对象

Window 对象作为客户端 JavaScript 的全局对象,它有一个 window 属性指向自身,这点在《JavaScript深入之变量对象》中讲到过。我们可以利用这个特性判断是否是 Window 对象。

function isWindow( obj ) {return obj != null && obj === obj.window;
}

isArrayLike

isArrayLike,看名字可能会让我们觉得这是判断类数组对象的,其实不仅仅是这样,jQuery 实现的 isArrayLike,数组和类数组都会返回 true。

因为源码比较简单,我们直接看源码:

function isArrayLike(obj) {// obj 必须有 length属性var length = !!obj && "length" in obj && obj.length;var typeRes = type(obj);// 排除掉函数和 Window 对象if (typeRes === "function" || isWindow(obj)) {return false;}return typeRes === "array" || length === 0 ||typeof length === "number" && length > 0 && (length - 1) in obj;
}

重点分析 return 这一行,使用了或语句,只要一个为 true,结果就返回 true。

所以如果 isArrayLike 返回true,至少要满足三个条件之一:

  1. 是数组
  2. 长度为 0
  3. lengths 属性是大于 0 的数字类型,并且obj[length - 1]必须存在

第一个就不说了,看第二个,为什么长度为 0 就可以直接判断为 true 呢?

那我们写个对象:

var obj = {a: 1, b: 2, length: 0}

isArrayLike 函数就会返回 true,那这个合理吗?

回答合不合理之前,我们先看一个例子:

function a(){console.log(isArrayLike(arguments))
}
a();

如果我们去掉length === 0 这个判断,就会打印 false,然而我们都知道 arguments 是一个类数组对象,这里是应该返回 true 的。

所以是不是为了放过空的 arguments 时也放过了一些存在争议的对象呢?

第三个条件:length 是数字,并且 length > 0 且最后一个元素存在。

为什么仅仅要求最后一个元素存在呢?

让我们先想下数组是不是可以这样写:

var arr = [,,3]

当我们写一个对应的类数组对象就是:

var arrLike = {2: 3,length: 3
}

也就是说当我们在数组中用逗号直接跳过的时候,我们认为该元素是不存在的,类数组对象中也就不用写这个元素,但是最后一个元素是一定要写的,要不然 length 的长度就不会是最后一个元素的 key 值加 1。比如数组可以这样写

var arr = [1,,];
console.log(arr.length) // 2

但是类数组对象就只能写成:

var arrLike = {0: 1,length: 1
}

所以符合条件的类数组对象是一定存在最后一个元素的!

这就是满足 isArrayLike 的三个条件,其实除了 jQuery 之外,很多库都有对 isArrayLike 的实现,比如 underscore:

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;var isArrayLike = function(collection) {var length = getLength(collection);return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

isElement

isElement 判断是不是 DOM 元素。

isElement = function(obj) {return !!(obj && obj.nodeType === 1);
};

结语

这一篇我们介绍了 jQuery 的 isPlainObject、isEmptyObject、isWindow、isArrayLike、以及 underscore 的 isElement 实现。我们可以看到,即使是 jQuery 这样优秀的库,一些方法的实现也并不是非常完美和严密的,但是最后为什么这么做,其实也是一种权衡,权衡所失与所得,正如玉伯在《从 JavaScript 数组去重谈性能优化》中讲到:

所有这些点,都必须脚踏实地在具体应用场景下去分析、去选择,要让场景说话。

相关文章:

JavaScript专题之类型判断(下)

参考原文&#xff1a;JavaScript专题之类型判断(下) 前言 在上篇《JavaScript专题之类型判断(上)》中&#xff0c;我们抄袭 jQuery 写了一个 type 函数&#xff0c;可以检测出常见的数据类型&#xff0c;然而在开发中还有更加复杂的判断&#xff0c;比如 plainObject、空对象…...

【VC 7/8】vCenter Server 基于文件的备份和还原Ⅲ—— 使用 SMB 协议备份 VC(VAMI 中文)

目录2.2 使用 SMB 协议备份 VC&#xff08;VAMI 中文&#xff09;&#xff08;1&#xff09;登录 vCenter Server 管理界面&#xff08;2&#xff09;进入备份页面&#xff08;3&#xff09;配置 Backup Schedule&#xff08;4&#xff09;开始备份&#xff08;5&#xff09;备…...

linux - 内核编译

一. 编译的实质基于头文件和c文件--->产生对象文件(.o)将所有的对象文件链接起来&#xff0c;产生可执行文件。内核的编译系统组成Makefile分布在内核源代码中的Makefile&#xff0c; 定义内核的编译规则&#xff0c;配合Kconfig使用。Kconfig配置文件&#xff0c;给用户提供…...

Spring——配置文件实现IOC和DI入门案例

现在先如图创建如下的Maven项目&#xff0c;在业务层和数据层分别写上对应的接口和实现类 在BookServiceImpl中创建一个BookDaoImpl对象&#xff0c;并调用里面的save()方法。 在测试类里面new一个bookservice的实现类&#xff0c;调用save()方法 输出如下图所示 要使用IOC容…...

机器学习100天(四十一):041 对偶支持向量机-公式推导

《机器学习100天》完整目录:目录 机器学习 100 天,今天讲的是:对偶支持向量机-公式推导! 本节主要延续上一节的内容,推导线性支持向量机的对偶形式。本节内容包含的数学理论和推导很多,我尽量简化其中的数学部分,只做感性的介绍,便于大家在理解的同时不受数学复杂公式…...

C语言下的signal()函数

signal()简介 signal() 函数是 C 语言中用于处理系统信号的函数。它在 signal.h 头文件中进行声明。信号用作进程间通信&#xff0c;报告异常行为&#xff0c;例如除零&#xff0c;或用户的一些按键组合&#xff0c;例如同时按下 Ctrl 与 C 键&#xff0c;产生信号 SIGINT。 …...

google独立站和与企业官网的区别是什么?

google独立站和与企业官网的区别是什么&#xff1f; 答案是&#xff1a;独立站通过谷歌SEO优化可以更好的获取自然排名的流量。 随着互联网的不断发展&#xff0c;企业越来越重视自身网站的建设和优化&#xff0c;而在企业网站建设中&#xff0c;很多人会犯一个常见的错误&am…...

Vue3---语法初探

目录 hello world 实现简易计时显示 反转字符串 显示隐藏 了解循环 了解双向绑定实现简易记事 设置鼠标悬停的文本 组件概念初探&#xff0c;进行组件代码拆分 hello world 最原始形态&#xff0c;找到 id 为 root 的标签&#xff0c;将 Vue 实例的模板放入标签之内 …...

esp8266WiFi模块通过MQTT连接华为云

esp8266WiFi模块通过MQTT连接华为云总结&#xff1a;一、 MQTT透传AT固件烧录二、 串口调试2.1 设置模块为STA模式2.2 连接WiFi2.3 设置MQTT的登陆用户名与密码2.4 设置MQTT的ClientID2.5 设置MQTT接入地址2.6 订阅设备属性上报的主题2.7 上传数据2.8 平台下发命令2.9 华为云物…...

苹果新卫星专利公布,苹果Find My功能知多少

根据美国商标和专利局&#xff08;USPTO&#xff09;公示的清单&#xff0c;苹果公司获得了一项新的卫星专利&#xff0c;可在非地面网络&#xff08;Non-Terrestrial Networks&#xff0c;NTN&#xff09;中定位用户设备&#xff08;iDevice、MacBook 等&#xff09;。 在专利…...

[ICLR‘22] DAB-DETR: Dynamic Anchor Boxes Are Better Queries for DETR

paper: https://arxiv.org/pdf/2201.12329.pdfcode: GitHub - IDEA-Research/DAB-DETR: [ICLR 2022] DAB-DETR: Dynamic Anchor Boxes are Better Queries for DETR将位置相关性计算显式的引入到decoder中&#xff0c;通过box坐标(x, y, w, h) 影响Q和K的相关性计算。特征图要有…...

双周赛99(贪心、数学、区间合并计算、换根DP)

文章目录双周赛99[6312. 最小和分割](https://leetcode.cn/problems/split-with-minimum-sum/)贪心[6311. 统计染色格子数](https://leetcode.cn/problems/count-total-number-of-colored-cells/)找规律[6313. 统计将重叠区间合并成组的方案数](https://leetcode.cn/problems/c…...

OpenText Exceed TurboX(ETX) 客户案例——弗吉尼亚理工大学

弗吉尼亚理工大学简化了高性能计算的使用。OpenText Exceed TurboX 提供高性能图形远程应用程序访问&#xff0c;提高工作效率 挑战 图形界面响应缓慢&#xff0c;影响用户使用&#xff1b; 对复制应用程序输出文件进行本地分析时&#xff0c;影响带宽和速度&#xff1b; 使用…...

【Python】torch.norm()用法解析

【Python】torch.norm()用法解析 文章目录【Python】torch.norm()用法解析1. 介绍1.1 p-范数1.2 Frobenius 范数1.3 核范数2. API3. 示例1. 介绍 torch.norm()是对输入的tensor求对应的范数。tensor的范数有以下三种&#xff1a; 1.1 p-范数 1.2 Frobenius 范数 即&#xff…...

C++核心编程<内存分区模型>(1)

C核心编程<内存分区模型>1.内存分区模型1.1内存分区模型概述1.2内存分区的意义1.3程序允许前1.3.1代码区1.3.2全局区1.3.2.1全局区的演示1.4程序运行后1.4.1栈区1.4.1.1栈区演示1.4.2堆区1.4.2.1堆区演示1.5new操作符1.5.1new操作的概述1.内存分区模型 1.1内存分区模型概…...

电路基础(1)电路模型和电路定律

电路中的电压、电流之间具有两种约束&#xff0c;一种是由电路元件决定的元件约束&#xff1b;另一种是元件间连接而引入的几何约束&#xff08;就是拓扑约束&#xff09;&#xff0c;后者由基尔霍夫定律来表达。基尔霍夫定律是集总参数电路的基本定律。 1.电路和电路模型电源又…...

pytest 基础

pytest安装 安装 pip install -U pytest 验证安装 pytest --version 约束&#xff1a; 所有的测试文件名都需要满足test_ *.py格式或* _test.py格式。 测试文件中的测试类以Test_开头&#xff0c;并且不能带有 init 方法。 测试类中可以包含一个或多个test_开头的函数。 步骤…...

软测入门(七)python操作数据文件(Json、yaml、csv、excel、xml)

python操作文件 txt文件 read() : 读取所有readline() : 读取一行readlines() : 读取所有&#xff0c;且以行为单位&#xff0c;放入list列表中 file open(r"F:\abc.txt", "r", encoding"utf-8") # 以utf-8格式读取文件 # 读取所有 # print…...

【小程序】django学习笔记1

网页能用&#xff0c;不知道小程序能不能用。应该能吧。。。。。创建django程序文件包&#xff0c;xxx处是给该文件夹起个名django-admin startproject xxx一个project是由很多个app&#xff08;小应用&#xff09;组成的在文件夹目录下创建一个app&#xff0c;xxx处给该app起个…...

MySQL常用函数整理

MySQL常用函数整理sql函数分类一、流程控制1、判断值为null或空字符串2、IF函数3、IFNULL函数4、CASE函数(1) 相当于switch case的作用(2) 相当于if elseif的作用5、COALESCE函数二、字符串类&#xff08;GBT答案&#xff09;1、用于select、insert等子句中2、用于where子句中其…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...