JavaScript空數(shù)組的every()方法實(shí)踐
JavaScript 語(yǔ)言的核心足夠大,以至于很容易誤解其某些部分的工作方式。我最近在重構(gòu)一些使用 every()
方法的代碼時(shí)發(fā)現(xiàn),我實(shí)際上并沒(méi)有完全理解其背后的邏輯。在我的腦海中,我假設(shè)回調(diào)函數(shù)必須被調(diào)用并返回 true
,every()
才會(huì)返回 true
,但實(shí)際情況并非如此。對(duì)于一個(gè)空數(shù)組,every()
無(wú)論回調(diào)函數(shù)是什么都會(huì)返回 true
,因?yàn)槟莻€(gè)回調(diào)函數(shù)從未被調(diào)用??紤]以下情況:
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
在這個(gè)例子的每種情況下,調(diào)用 every()
都是為了檢查數(shù)組中的每一項(xiàng)是否為數(shù)字。前四個(gè)調(diào)用相當(dāng)直接,every()
產(chǎn)生了預(yù)期的結(jié)果?,F(xiàn)在考慮這些例子:
[].every(() => true); // true [].every(() => false); // true
這可能更令人驚訝:無(wú)論是返回 true
還是 false
的回調(diào),結(jié)果都是一樣的。唯一的原因是如果回調(diào)沒(méi)有被調(diào)用,every()
的默認(rèn)值是 true
。但是,為什么一個(gè)空數(shù)組會(huì)對(duì) every()
返回 true
,當(dāng)沒(méi)有值去執(zhí)行回調(diào)函數(shù)時(shí)呢?
要理解原因,重要的是要看看規(guī)范是如何描述這個(gè)方法的。
實(shí)現(xiàn) every()
ECMA-262 定義了一個(gè) 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()
假設(shè)結(jié)果是 true
,并且只有當(dāng)回調(diào)函數(shù)對(duì)數(shù)組中的任何一個(gè)條目返回 false
時(shí),才會(huì)返回 false
。如果數(shù)組中沒(méi)有條目,則沒(méi)有執(zhí)行回調(diào)函數(shù)的機(jī)會(huì),因此,該方法無(wú)法返回 false
。
現(xiàn)在的問(wèn)題是:every()
為什么會(huì)這樣表現(xiàn)呢?
數(shù)學(xué)和 JavaScript 中的“全稱量詞”
MDN 頁(yè)面提供了為什么 every()
對(duì)一個(gè)空數(shù)組返回 true
的答案:
every 表現(xiàn)得像數(shù)學(xué)中的“全稱量詞”。特別是對(duì)于一個(gè)空數(shù)組,它返回 true。(空集合中的所有元素默認(rèn)滿足任何給定條件是一種空洞真理。)
空洞真理 是指如果給定條件(稱為前提)不能滿足(即,給定條件不是真的),那么某事是真的。把它轉(zhuǎn)回 JavaScript 方面,every()
對(duì)一個(gè)空集返回 true
是因?yàn)闆](méi)有辦法調(diào)用回調(diào)。回調(diào)代表要測(cè)試的條件,如果因?yàn)閿?shù)組中沒(méi)有值而無(wú)法執(zhí)行它,則 every()
必須返回 true
。
“全稱量詞”是數(shù)學(xué)中一個(gè)更大主題的一部分,稱為普遍量化,它允許你對(duì)數(shù)據(jù)集合進(jìn)行推理。鑒于 JavaScript 數(shù)組在執(zhí)行數(shù)學(xué)計(jì)算中的重要性,尤其是與類型化數(shù)組一起使用,自然會(huì)支持這種操作。而且 every()
不是唯一的例子。
數(shù)學(xué)和 JavaScript 中的“存在量詞”
JavaScript 的 some()
方法實(shí)現(xiàn)了存在量化(“存在”有時(shí)也稱為“存在”或“對(duì)于某些”)中的“存在”量詞。"存在" 量詞聲明,對(duì)于任何空集合,結(jié)果是假。因此,some()
方法對(duì)一個(gè)空集返回 false
,并且它也不執(zhí)行回調(diào)。這里有一些例子(雙關(guān)語(yǔ)):
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
其他語(yǔ)言中的量化
JavaScript 不是唯一一個(gè)為集合或迭代器實(shí)現(xiàn)了量化方法的編程語(yǔ)言:
- Python:
all()
函數(shù)實(shí)現(xiàn)了“全稱” ,而any()
函數(shù)實(shí)現(xiàn)了“存在”。 - Rust:
Iterator::all()
方法實(shí)現(xiàn)了“全稱”,而any()
方法實(shí)現(xiàn)了“存在”。
因此,JavaScript 憑借 every()
和 some()
與眾不同。
“全稱” every() 的含義
不管你是否認(rèn)為 every()
的行為違反直覺(jué),這都是值得討論的。然而,不管你的觀點(diǎn)如何,你都需要意識(shí)到 every()
的“全稱”本質(zhì),以避免錯(cuò)誤。簡(jiǎn)而言之,如果你使用 every()
或可能為空的數(shù)組時(shí),你應(yīng)該事先進(jìn)行明確的檢查。例如,如果你有一個(gè)依賴數(shù)字?jǐn)?shù)組的操作,而空數(shù)組會(huì)導(dǎo)致操作失敗,那么你應(yīng)該在使用 every()
之前檢查數(shù)組是否為空:
function doSomethingWithNumbers(numbers) { // 首先檢查長(zhǎng)度 if (numbers.length === 0) { throw new TypeError("Numbers array is empty; this method requires at least one number."); } // 現(xiàn)在用 every() 檢查 if (numbers.every(isNumber)) { operationRequiringNonEmptyArray(numbers); } }
再次強(qiáng)調(diào),只有當(dāng)你有一個(gè)不應(yīng)該在空的時(shí)候用于操作的數(shù)組時(shí),這個(gè)額外的檢查才是重要的;否則,你可以避免這個(gè)額外的檢查。
結(jié)論
雖然我對(duì) every()
對(duì)一個(gè)空數(shù)組的行為感到驚訝,但一旦你理解了這個(gè)操作的更廣泛上下文以及這個(gè)功能在不同語(yǔ)言中的普及,這就講得通了。如果你對(duì)這個(gè)行為也感到困惑,那么我建議你在遇到 every()
調(diào)用時(shí)改變你的閱讀方式。不要把 every()
看作是“這個(gè)數(shù)組的每一項(xiàng)是否滿足這個(gè)條件?”而是看作是,“數(shù)組中是否有任何一項(xiàng)不滿足這個(gè)條件?”這種思維的轉(zhuǎn)變可以幫助你避免未來(lái)在你的 JavaScript 代碼中出現(xiàn)錯(cuò)誤。
原文作者:Nicholas C. Zakas (https://humanwhocodes.com/blog/2023/09/javascript-wtf-why-does-every-return-true-for-empty-array/)
到此這篇關(guān)于JavaScript空數(shù)組的every()方法實(shí)踐的文章就介紹到這了,更多相關(guān)JavaScript空數(shù)組every()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript同步Import,同步調(diào)用外部js的方法
javascript同步Import,同步調(diào)用外部js的實(shí)現(xiàn)代碼,測(cè)試確實(shí)可用2008-07-07js實(shí)現(xiàn)短信發(fā)送倒計(jì)時(shí)功能(正則驗(yàn)證)
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)短信發(fā)送倒計(jì)時(shí)功能,包含正則驗(yàn)證,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02利用jsonp跨域調(diào)用百度js實(shí)現(xiàn)搜索框智能提示
這篇文章主要為大家詳細(xì)介紹了使用jsonp跨域調(diào)用百度js實(shí)現(xiàn)搜索框智能提示,感興趣的小伙伴們可以參考一下2016-08-08用Fundebug插件記錄網(wǎng)絡(luò)請(qǐng)求異常的方法
這篇文章主要介紹了用Fundebug插件記錄網(wǎng)絡(luò)請(qǐng)求異常的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02Three.js如何實(shí)現(xiàn)霧化效果示例代碼
霧化效果是3D的比較常見(jiàn)的特性,在游戲中見(jiàn)到的煙霧、爆炸火焰以及白云等效果都是霧化的結(jié)果,下面這篇文章主要給大家介紹了關(guān)于Three.js如何實(shí)現(xiàn)霧化效果的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-09-09js實(shí)現(xiàn)同一個(gè)頁(yè)面多個(gè)漸變效果的方法
這篇文章主要介紹了js實(shí)現(xiàn)同一個(gè)頁(yè)面多個(gè)漸變效果的方法,涉及javascript操作漸變效果的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04用JS操作FRAME中的IFRAME及其內(nèi)容的實(shí)現(xiàn)代碼
一直都需要這樣的東西,發(fā)現(xiàn)了這個(gè)好東西,一定要研究下2008-07-07