记录--JavaScript 令人惊讶的一点:对于空数组every()方法返回true
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
function isNumber(value) {
return typeof value === "number";
} [1].every(isNumber); // true
["1"].every(isNumber); // false
[1, 2, 3].every(isNumber); // true
[1, "2", 3].every(isNumber); // false
[].every(isNumber); // true
在此示例的每种情况下,均调用 every ()来检查数组中的每一项是否为数字。前四个调用相当简单,每个都会产生预期的结果。考虑如下的例子:
[].every(() => true); // true
[].every(() => false); // true
这样的结果可能更令人感到惊讶: 对于every(),返回 true 或 false 的回调都具有相同的结果。发生这种情况的唯一原因是调用回调函数没有被调用,并且 every ()的默认返回值为 true。但是,当没有值可以用来运行回调函数时,为什么空数组对 every ()返回 true呢?
为了理解其中的原因,重要的是看看规范是如何描述这种方法的。
实现every()方法
ECMA-262定义了一个 Array.Prototype.every ()算法,该算法大致可以翻译成这段 JavaScript 代码:
Array.prototype.every = function(callbackfn, thisArg) {
const O = this;
const len = O.length;
if (typeof callbackfn !== "function") {
throw new TypeError("Callback isn't callable");
}
let k = 0;
while (k < len) {
const Pk = String(k);
const kPresent = O.hasOwnProperty(Pk);
if (kPresent) {
const kValue = O[Pk];
const testResult = Boolean(callbackfn.call(thisArg, kValue, k, O));
if (testResult === false) {
return false;
}
}
k = k + 1;
}
return true;
};
从代码中可以看出,every ()假定结果为 true,并且只有在回调函数对数组中的任何一项返回 false 时才返回 false。如果数组中没有元素,那么就没有机会执行回调函数,因此方法就没有办法返回 false。
现在的问题是:为什么every()要这样做?
数学和 JavaScript 中的全称量词
译者注:全称量词是指“所有”的概念,常用符号为∀。例如,对于集合S中的元素x,可以表示为∀x∈S,意为“对于S中的每一个元素x都成立”
MDN 提供了为什么 every ()对于空数组返回 true 的答案:
every 和数学中的全称量词"任意(∀)"类似。特别的,对于空数组,它只返回 true。
(这种情况属于无条件正确,因为空集的所有元素都符合给定的条件。)
无条件正确是一个数学概念,它意味着如果一个给定的条件(称为先行条件)不能被满足(也就是说,给定的条件是不真实的) ,那么某些东西就是真的。要将其应用到 JavaScript 中,那就是every ()对于空数组返回 true,因为没有办法调用回调函数 。回调代表了要测试的条件,如果由于数组中没有值而无法执行,那么 every ()必须返回 true。
全称量词是数学中一个更大的主题的一部分,这个主题被称为“全称量化”,它允许你对数据集进行推理。考虑到 JavaScript 数组对于执行数学计算的重要性,特别是对于类型化数组,内置支持这种操作是有意义的。要知道,every()并不是唯一的例子。
数学和 JavaScript 中的存在量词
译者注: 存在量词是指“存在”的概念,常用符号为∃。例如,对于集合S中的元素x,可以表示为∃x∈S,意为“存在S中的一个元素x”
JavaScript 的some()方法实现了存在量词。“存在”量词指出,对于任何空集,结果都是 false。因此,some ()方法对于空数组返回 false,并且也不执行回调函数。下面是一些例子:
function isNumber(value) {
return typeof value === "number";
}
[1].some(isNumber); // true
["1"].some(isNumber); // false
[1, 2, 3].some(isNumber); // true
[1, "2", 3].some(isNumber); // true
[].some(isNumber); // false
[].some(() => true); // false
[].some(() => false); // false
其他语言对量词的实现
JavaScript 并不是唯一的一种为集合或可迭代对象实现了量词相关方法的编程语言:
Python: all ()函数实现全称量词,而 any ()函数实现了存在量词。
Rust: Iterator: : all ()函数实现了全称量词,而 any ()函数实现了存在量词。
因此,JavaScript 与 every ()和 some ()都有着良好的合作关系。
意味着全称量词的every()
你是否认为evey()的行为是违反直觉的?这可有待商榷。然而,不管您的观点如何,您都需要了every()所具有的全程量词的性质以避免错误。简而言之,如果可能为空的数组使用了every (),则应该事先添加一个显式检查。例如,如果您有一个依赖于数字数组的操作,并且该操作将以空数组失败,那么您应该在使用 every ()之前检查该数组是否为空:
function doSomethingWithNumbers(numbers) {
// first check the length
if (numbers.length === 0) {
throw new TypeError("Numbers array is empty; this method requires at least one number.");
}
// now check with every()
if (numbers.every(isNumber)) {
operationRequiringNonEmptyArray(numbers);
}
}
注意,只有当数组为空时不能执行某操作时,这样做是有必须要的。否则,可以避免这种额外的检查。
总结
虽然我对空数组上执行 every ()方法的执行结果感到惊讶,可是当我了解了某个操作的更大范围的上下文以及这种功能在各种语言之间的表现时,我就会感到释然。如果您也对这种行为感到困惑,那么我建议您在遇到every()的调用时改变你对它的理解。不再将 every ()读作“此数组中的每个项是否匹配此条件?”而是读作“数组中有没有不符合条件的项?”这种思维上的转变可以帮助您在以后的 JavaScript 代码中避免错误。
本文转载于:
https://juejin.cn/post/7279093851000062010
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--JavaScript 令人惊讶的一点:对于空数组every()方法返回true的更多相关文章
- 空数组判断false、true的情况
- JavaScript中判断变量类型最简洁的实现方法以及自动类型转换(#################################)
这篇文章主要介绍了JavaScript中判断整字类型最简洁的实现方法,本文给出多个判断整数的方法,最后总结出一个最短.最简洁的实现方法,需要的朋友可以参考下 我们知道JavaScript提供了type ...
- js 判断是否为空对象、空数组
当需要判断参数是否为空时,总希望 js 能够提供原生的判断方法,可惜并没有,只能自己封装了. function isEmpty(obj) { // 检验 undefined 和 null if(!ob ...
- node.js 开发桌面程序, 10个令人惊讶的NodeJS开源项目
用 node-webkit 开源框架. 做企业站,杠杠地 包括电子书和支付宝系统都是node开发的,. 接收传感器发送的数据再运算...对水泵.风机.空调这些硬件进行远程控制. 细数10个令人惊讶的N ...
- javascript中怎么判断对象{}为空
有时候通过AJAX方法调用返回的是一个JSON对象,而这个对象可能在开发过程中会没有数据是一个空{}. JavaScript判断object/json 是否为空,可以使用jQuery的isEmptyO ...
- 【06】Firebug记录Javascript日志
Firebug记录Javascript日志 你可以使用Firebug来生成日志. 这有助于我们调试web页面并发现页面的错误. 在Firefox浏览器中执行以下代码: <!DOCTYPE HTM ...
- JavaScript的json和Array及Array数组的使用方法
1.关于json JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集.也可以称为数据集和数组类似,能够存数据! //Ar ...
- javascript中数组的方法你真的都了解吗?
本篇文章主要讲述ES5中的数组,包括数组两种创建方式,属性,以及 9 大类 ,总共23个操作方法,非常全面,看完之后ES5数组这一部分基本都了解了,下一篇文章,我会讲述ES6中对数组的加成,新增了哪些 ...
- JavaScript进阶 - 第3章 一起组团(数组)
第3章 一起组团(数组) 3-1 一起组团(什么是数组) 我们知道变量用来存储数据,一个变量只能存储一个内容.假设你想存储10个人的姓名或者存储20个人的数学成绩,就需要10个或20个变量来存储,如果 ...
- JavaScript中操作数组的方法
JavaScript Array 对象 对数组操作的方法分为两种 一种是会改变原始数组的变异方法,还有一种是不会改变原始数组的非变异方法. 总结 巧记 Push() 尾部添加 pop() 尾部删除 U ...
随机推荐
- RocketMQ—RocketMQ消费重试和死信消息
RocketMQ-RocketMQ消费重试和死信消息 消费重试 生产者重试 设置重试的代码如下 // 失败的情况重发3次 producer.setRetryTimesWhenSendFailed(3) ...
- 基于OpenTelemetry实现Java微服务调用链跟踪
本文分享自华为云社区<基于OpenTelemetry实现Java微服务调用链跟踪>,作者: 可以交个朋友. 一 背景 随着业务的发展,所有的系统都会走向微服务化体系,微服务进行拆分后,服务 ...
- NC52867 Highway
题目链接 题目 题目描述 In ICPCCamp there were n towns conveniently numbered with \(1, 2, \dots, n\) connected ...
- 从零开始手写 mybatis(一)MVP 版本
什么是 MyBatis ? MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集. MyB ...
- 基于Android的“哲学家就餐问题”防死锁的设计与实现
1问题描述 如图1.1,有5个哲学家围着一个大圆桌就餐.哲学家和筷子都按逆时针顺序编号,每个哲学家的编号与他左边的筷子的编号一致. 规定如下: (1)哲学家之间不相互交流: (2)哲学家只做两件事:吃 ...
- display的值及作用
display的值及作用 display属性可以设置元素的内部和外部显示类型,元素的外部显示类型将决定该元素在流式布局中的表现,例如块级或内联元素,元素的内部显示类型可以控制其子元素的布局,例如gri ...
- MySQL日志:slow query log
ySQL的慢查询日志可以用来找出执行时间过长的查询语句,并进行针对性的优化. 一.slow log相关参数 以下参数都是动态参数,可以在实例运行时修改. slow_query_log=1 #是否启 ...
- SpringBoot中Redis的基础使用
基础使用 首先引入依赖 <!-- redis依赖--> <dependency> <groupId>org.springframework.boot</gro ...
- 如何设置 vcpkg 依赖特定编译器
最近项目要部署到 gitlab-ci 上,所以远程机器上也要安装好编译环境 在相关的环境安装完后,发现编译项目时提示找不到三方库的符号文件 看到这个错误的第一反应就是依赖库的版本不对,因为远程机器上不 ...
- win32 - service的创建
参考这篇教程:Simple Windows Service in C++ 安装service需要在管理员权限下运行cmd,并输入下面的命令行 C:\>sc create "My Sam ...