記錄--JavaScript 令人驚訝的一點:對於空數組every()方法返回true

来源:https://www.cnblogs.com/smileZAZ/archive/2023/09/18/17712752.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 JavaScript 語言的內核足夠大,導致我們很容易誤解它的某些部分是如何工作的。我最近重構了一些使用 every ()方法的代碼,並且發現我並不真正理解every()的邏輯。在我看來,我認為回調函數必須被調用並返回 true的時候ev ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

JavaScript 語言的內核足夠大,導致我們很容易誤解它的某些部分是如何工作的。我最近重構了一些使用 every ()方法的代碼,並且發現我並不真正理解every()的邏輯。在我看來,我認為回調函數必須被調用並返回 true的時候every() 才能返回 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(() => 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

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Ubuntu20.04安裝Mysql8主從 一.主資料庫安裝 1.下載安裝包並初始化資料庫 # 進入目錄 cd /opt # 下載安裝包 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x ...
  • 本文分享自華為雲社區《DTSE Tech Talk | 第43期:數倉數據可靠保證——物理細粒度備份恢復》,作者:華為雲社區精選。 大數據時代,數據對企業的重要性不言而喻,如果發生數據丟失或因為誤操作而造成數據丟失,將對企業的經營決策帶來不可估量的損失。本期《備份恢復全掌握,數倉數據更安全》的主題直 ...
  • UUID(通用唯一識別碼)是由32個十六進位數組成的無序字元串,通過一定的演算法計算出來。為了保證其唯一性,UUID規範定義了包括網卡MAC地址、時間戳、名字空間(Namespace)、隨機或偽隨機數、時序等元素,以及從這些元素生成UUID的演算法。一般來說,演算法可以保證任何地方產生的任意一個UUID都... ...
  • Redis是游戲資料庫重要選型之一,華為雲GaussDB(for Redis)能及時上報用戶下線行為,被廣泛應用於排行榜等多種業務場景。 ...
  • Ubuntu20.04安裝Postgres主從備份 一.查看可安裝的Postgres包 #列出相關的軟體包,這裡安裝的是14版本 apt list | grep -w postgresql-14 | tail -1 #下載Postgres apt install -y postgresql-14/f ...
  • 基於OpenHarmony和華為雲平臺打造的智能家居設備,分別為智能門鎖,儲物精靈 NFC版,儲物精靈Pro版三個設備。 ...
  • 之前在 《iOS16新特性:靈動島適配開發與到家業務場景結合的探索實踐》 里介紹了iOS16新的特性:實時更新(Live Activity)中靈動島的適配流程,但其實除了靈動島的展示樣式,Live Activity還有一種非常實用的應用場景,那就是鎖屏界面實時狀態更新: ...
  • 前端遠程調試方案 Chii 的使用經驗分享 Chii 是與 weinre 一樣的遠程調試工具 ,主要是將 web inspector 替換為最新的 chrome devtools frontend 監控列表頁面可以看到網站的標題鏈接,IP,useragent,可以快速定位調試頁面,監控頁信息完善,支 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...