JavaScript空数组的every()方法实践

 更新时间:2024年03月11日 09:03:04   作者:Apifox.  
every()方法用于检测数组中的所有元素是否都满足指定条件, 本文主要介绍了JavaScript空数组的every()方法实践,具有一定的参考价值,感兴趣的可以了解一下

JavaScript 语言的核心足够大,以至于很容易误解其某些部分的工作方式。我最近在重构一些使用 every() 方法的代码时发现,我实际上并没有完全理解其背后的逻辑。在我的脑海中,我假设回调函数必须被调用并返回 trueevery() 才会返回 true,但实际情况并非如此。对于一个空数组,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() 产生了预期的结果。现在考虑这些例子:

[].every(() => true);           // true
[].every(() => false);          // true

这可能更令人惊讶:无论是返回 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 中的“全称量词”

MDN 页面提供了为什么 every() 对一个空数组返回 true 的答案:

every 表现得像数学中的“全称量词”。特别是对于一个空数组,它返回 true。(空集合中的所有元素默认满足任何给定条件是一种空洞真理。)

空洞真理 是指如果给定条件(称为前提)不能满足(即,给定条件不是真的),那么某事是真的。把它转回 JavaScript 方面,every() 对一个空集返回 true 是因为没有办法调用回调。回调代表要测试的条件,如果因为数组中没有值而无法执行它,则 every() 必须返回 true

“全称量词”是数学中一个更大主题的一部分,称为普遍量化,它允许你对数据集合进行推理。鉴于 JavaScript 数组在执行数学计算中的重要性,尤其是与类型化数组一起使用,自然会支持这种操作。而且 every() 不是唯一的例子。

数学和 JavaScript 中的“存在量词”

JavaScript 的 some() 方法实现了存在量化(“存在”有时也称为“存在”或“对于某些”)中的“存在”量词。"存在" 量词声明,对于任何空集合,结果是假。因此,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() 的含义

不管你是否认为 every() 的行为违反直觉,这都是值得讨论的。然而,不管你的观点如何,你都需要意识到 every() 的“全称”本质,以避免错误。简而言之,如果你使用 every() 或可能为空的数组时,你应该事先进行明确的检查。例如,如果你有一个依赖数字数组的操作,而空数组会导致操作失败,那么你应该在使用 every() 之前检查数组是否为空:

function doSomethingWithNumbers(numbers) {

    // 首先检查长度
    if (numbers.length === 0) {
        throw new TypeError("Numbers array is empty; this method requires at least one number.");
    }

    // 现在用 every() 检查
    if (numbers.every(isNumber)) {
        operationRequiringNonEmptyArray(numbers);
    }

}

再次强调,只有当你有一个不应该在空的时候用于操作的数组时,这个额外的检查才是重要的;否则,你可以避免这个额外的检查。

结论

虽然我对 every() 对一个空数组的行为感到惊讶,但一旦你理解了这个操作的更广泛上下文以及这个功能在不同语言中的普及,这就讲得通了。如果你对这个行为也感到困惑,那么我建议你在遇到 every() 调用时改变你的阅读方式。不要把 every() 看作是“这个数组的每一项是否满足这个条件?”而是看作是,“数组中是否有任何一项不满足这个条件?”这种思维的转变可以帮助你避免未来在你的 JavaScript 代码中出现错误。

原文作者:Nicholas C. Zakas (https://humanwhocodes.com/blog/2023/09/javascript-wtf-why-does-every-return-true-for-empty-array/)

到此这篇关于JavaScript空数组的every()方法实践的文章就介绍到这了,更多相关JavaScript空数组every()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • uniapp实现审批流程的具体操作步骤

    uniapp实现审批流程的具体操作步骤

    这篇文章主要介绍了uniapp实现审批流程的具体操作方法,实现思路大概是需要要定义一个变量,记录当前激活的步骤,通过数组的长度来循环数据,如果有就采用3元一次进行选择,具体实现步骤跟随小编一起看看吧
    2024-03-03
  • js中script的上下放置区别,Dom的增删改创建操作实例分析

    js中script的上下放置区别,Dom的增删改创建操作实例分析

    这篇文章主要介绍了js中script的上下放置区别,Dom的增删改创建操作,结合实例形式分析了JavaScript基本dom事件、script在head和body中放置的区别、以及Dom的增删改创建等相关操作技巧,需要的朋友可以参考下
    2019-12-12
  • Javascript中parseInt的正确使用方式

    Javascript中parseInt的正确使用方式

    今天小编就为大家分享一篇关于Javascript中parseInt的正确使用方式,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • JavaScript数组的随机排序方法详解

    JavaScript数组的随机排序方法详解

    在前端开发中,我们经常需要对数组进行随机排序,例如在游戏、抽奖、数据随机展示等场景中,JavaScript 提供了多种方式来实现数组的随机排序,本文将详细介绍不同的方法,并分析它们的优缺点,帮助开发者在不同场景下选择合适的解决方案,需要的朋友可以参考下
    2025-03-03
  • Web打印解决方案之证件套打的实现思路

    Web打印解决方案之证件套打的实现思路

    这篇文章主要介绍了Web打印解决方案之证件套打的实现思路的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-08-08
  • 原生JavaScript实现轮播图

    原生JavaScript实现轮播图

    这篇文章主要为大家详细介绍了原生JavaScript实现轮播图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • 深入浅出理解JavaScript闭包的功能与用法

    深入浅出理解JavaScript闭包的功能与用法

    这篇文章主要介绍了深入浅出理解JavaScript闭包的功能与用法,结合实例形式从变量、函数的内部属性与作用域链分析了javascript闭包的相关概念、功能与使用技巧,需要的朋友可以参考下
    2018-08-08
  • 一个可以得到元素真实的背景颜色的javascript脚本

    一个可以得到元素真实的背景颜色的javascript脚本

    一个可以得到元素真实的背景颜色的javascript脚本...
    2007-07-07
  • cnblogs csdn 代码运行框实现代码

    cnblogs csdn 代码运行框实现代码

    大家用cnblogs,csdn博客发布技术文档的时候,可以用下面的代码实现运行功能。当然大家看了源码就会发现其实方法还有很多。有更好的方法就发布一下啊。
    2009-11-11
  • bootstrap table实现双击可编辑、添加、删除行功能

    bootstrap table实现双击可编辑、添加、删除行功能

    这篇文章主要为大家详细介绍了bootstrap table实现双击可编辑、添加、删除行功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09

最新评论