当前位置: 首页 > 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子句中其…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

《Offer来了:Java面试核心知识点精讲》大纲

文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...

从实验室到产业:IndexTTS 在六大核心场景的落地实践

一、内容创作&#xff1a;重构数字内容生产范式 在短视频创作领域&#xff0c;IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色&#xff0c;生成的 “各位吴彦祖们大家好” 语音相似度达 97%&#xff0c;单条视频播放量突破百万…...