梳理 JavaScript 中空數組調用 every方法返回true 帶來驚訝的問題

前言

人生總是在意外之中. 情況大概是這樣的. 前兩天版本上線以后, 無意中發現了一個bug, 雖然不是很大, 為了不讓用戶使用時感覺到問題. 還是對著一個小小的bug進行了修復, 并重新在上線一次, 雖然問題不大, 但帶來的時間成本還是存在的. 以及上線后用戶體驗并不是很好.

問題產生的原因就在于JavaScript數組遍歷方法中對于空數組返回值的問題. 空數組遍歷的知識點, 在學習的過程中, 相信你肯定也接觸過, 學習過. 但在使用時往往會忽略這一點.

我們以every為例


1. every 基本使用

對于every遍歷方法, 這里就不過多闡述了. 主要就是遍歷數組中每個元素, 執行回調函數, 當所有的元素都返回true時, 結果是true, 只要有一次遍歷時, 回調函數返回false結果就是false


示例:

let arr = [40,50,60,10,20,30]// 判斷數組中所有的元素是否都大于5
let bol = arr.every((item) => item > 5)
console.log('bol', bol)
// 輸出結果: bol true// 判斷數組中所有的元素是否都大于
let bol2 = arr.every((item) => item > 10)
console.log('bol2', bol2)
// 輸出結果: bol2 false

在這個示例中, 第一次調用every 時, 會遍歷所有的數組元素, 因為每一個元素都大于5, 所以回調函數會執行6次, 每次都返回true, every遍歷方法最終返回true, 表示數組中每個元素都符合要求


第二次遍歷時, 只會遍歷4次, 因為在遍歷到10 時, 回調函數返回false, 此時數組后面的元素就不需要再遍歷了. 該false已經確定了最終的結果, false表示數組中包含不符號要求的元素.


every遍歷方法并不需要關心具體是第幾項元素不符合要求. 該方法的作用就是判斷數組中是否是每一項都符合要求


2. every 空數組的問題

我們先說一下最終的結果, 空數組使用every時, 每次結果都返回true

示例:

let arr = []// 固定返回true
let bol = arr.every((item) => true)
console.log('bol', bol)
// 輸出結果: bol true// 回調函數固定返回false
let bol2 = arr.every((item) => {console.log('every')return false
})
console.log('bol2', bol2);
// bol2 true

示例中, 我們對于空數組使用every遍歷方法, 無論回調函數返回的是true,還是false最終的結果都是true


我們在回調函數中添加console.log("every")記錄回調函數是否執行. 從運行結果來看, 會調函數并沒有執行. 空數組中沒有元素, 并不會執行回調函數, 也就意味這回調函數中返回的是什么值都毫無意義.

every遍歷方法最終的結果true顯然是一個默認值. 可以理解為調用every時, 默認返回值就是true, 然后遍歷元素,執行回調函數, 只要有一次回調函數返回的false, 則作為最終結果返回false并結束遍歷.


3. 規范描述

根據ECMA-262 官方描述, every方法的邏輯如下
在這里插入圖片描述

這里對于最終返回值, 我將其框選出來. 通過官方描述, 最終的結果有兩種情況, 其一就是默認返回true, 其二是根據回調函數執行的結果返回false,


這里我們根據表述, 自定義一個函數模擬every方法

示例

// 參數接受一個回調函數Array.prototype.myEvery = (callbackfn, thisArg) => {// 獲取this, 通過數組調用該方法, this 即為數組const O = this;// 獲取數組長度const len = O.length;// 確認參數callback 是一個函數. 否則報錯if(typeof callbackfn !== "function"){throw new TypeError(typeof callbackfn + "is not a function")}// 遍歷數組let k = 0; while(k  < len){// 轉為字符串const Pk = String(key)// 判斷下標是否為數組本身的屬性const kPresent = O.hasOwnProperty(Pk);if(kPresent){// 獲取數組元素const kValue = O[PK]// 調用回調函數, 獲取回調函數的結果const testResult = Boolean( callbackfn.call(this.Arg, kValue, k, O))// 如果回調函數返回false, 則停止循環, 整體返回falseif(testResult === false){return false}}k++}// 數組元素循環完畢, 回調函數都沒有返回false, 則表示數組每一項否符合要求// 最終返回truereturn true}

從代碼中可以看出,every ()默認返回為 true,并且只有在回調函數執行返回 false 時才返回 false。如果數組中沒有元素,那么就沒有機會執行回調函數,因此方法就沒有辦法返回 false,只會返回默認值true


4. 場景描述

在工作中發生問題場景是這樣的, 在使用vue開發, 父組件給子組件傳參. 期望傳入的 參數在子組件的本身數據中都包含, 則不執行后續邏輯, 如果傳入的數據, 在子組件數據中有不存的項, 則更新子組件數據.

這里我將復雜業務邏輯簡化為JavaScript方法的調用.

示例:

let cacheArray = [10,20,30];
function update (arr) {// 判斷傳入的數組每一項存在于cacheArray 中const result = arr.every((item) => cacheArray.includes(item))// 條件為true, 則表示傳入數組中的數據都存在, 則不執行后續邏輯,// false, 更新cacheArray 數據, 并執行后續邏輯if(!result){cacheArray = [...arr]console.log('cacheArray', cacheArray)}
}

這個示例代碼在表面上看沒有任何問題, 但如果你想清空cacheArray數組. 你會發現調用update方法做不到,

當你調用update方法,并傳入一個[]時, 空數組調用every的結果始終是true, 所以后面取反的結果始終為false, 根本執行更新cacheArray數組的代碼.


發現問題點, 解決方案就很簡單了, 修改一下判斷條件, 當參數為空數組時. length必然是0, 通過判斷是空數組, 根據邏輯運算符的||的短路算法規則, 不需再去判斷!result

修改判斷條件

if(!arr.length || !result){cacheArray = [...arr]console.log('cacheArray', cacheArray)
}

5. 總結

這就是空數組給功能帶來的問題. 所以有的時候, 真的不是我們學習了所有知識, 我們就能做到萬無一失. 在工作中存在很多復雜的邏輯, 一個疏忽, 或沒有考慮細致都會帶來問題. 不是不會, 而是所有業務邏輯交織在一起. 難免帶來一些邏輯上的遺漏


對于some方法也會有相同的問題, 對于空數組會始終返回false, 這個留給你自己探討

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14027.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14027.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14027.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM學習-垃圾收集器(二)

Serial回收器&#xff1a;串行回收 Serial收集器是最基本、歷史最悠久的收集器JDK1.3之前新生代唯一的選擇Hotpot中Client模式下的默認新生代垃圾收集器采用復制算法&#xff0c;串行回收“Stop-the-world”機制的方式執行內存回收除了年輕代之外&#xff0c;Serial收集器還提…

TG-5006CG溫補晶振在WiFi6無線路由器模塊的應用

WiFi6無線路由器是采用了wiFi6技術的無線網絡設備&#xff0c;旨在為家庭、辦公室或其他場所提供高速、穩定的無線網絡連接。它不僅能實現更高的數據傳輸速率和更低的延遲&#xff0c;還提供了更先進的加密和安全措施&#xff0c;確保用戶數據安全。為了支持這些高級功能&#…

深入 Rust 標準庫,Rust標準庫源代碼系統分析

系列文章目錄 送書第一期 《用戶畫像&#xff1a;平臺構建與業務實踐》 送書活動之抽獎工具的打造 《獲取博客評論用戶抽取幸運中獎者》 送書第二期 《Spring Cloud Alibaba核心技術與實戰案例》 送書第三期 《深入淺出Java虛擬機》 送書第四期 《AI時代項目經理成長之道》 …

Elasticsearch集群部署以及認證配置

文檔地址&#xff1a; 官網文檔地址&#xff1a; https://www.elastic.co/guide/index.html rpm包/源碼下載地址&#xff1a;https://www.elastic.co/cn/downloads 源碼安裝-環境準備&#xff1a; node-01 192.168.95.174 node-02 192.168.95.173 node-03 …

關于Mysql基本概念的理解

系列文章 關于時間復雜度o(1), o(n), o(logn), o(nlogn)的理解 關于HashMap的哈希碰撞、拉鏈法和key的哈希函數設計 關于JVM內存模型和堆內存模型的理解 關于代理模式的理解 關于Mysql基本概念的理解 關于軟件設計模式的理解 文章目錄 前言一、事務隔離級別二、存儲引擎1.…

【Python爬蟲】案例_斗魚

聲明&#xff1a;案例只用于學習&#xff0c;不得惡意使用 要求&#xff1a;獲取直播間標題、類型、主播、熱度&#xff0c;并實現翻頁 定位隨著網站更新可能不會實現&#xff0c;請自行更改 from selenium import webdriver from selenium.webdriver.chrome.options import…

【uniapp】CSS實現多行文本展開收起的文字環繞效果

1. 效果圖 收起狀態 展開狀態 2. 代碼實現 <view class"word-wrap" id"descriptionTxt"><view class"fold-text" v-if"isFold"><text class"fold-btn" click"changFold">全文</text&g…

【網絡安全】Linux 應急響應-溯源-系統日志排查知識點

Linux 應急響應-溯源-系統日志排查知識點匯總 1. 查看當前已經登錄到系統的用戶 (w 命令) w2. 查看所有用戶最近一次登錄 (lastlog 命令) lastlog lastlog | grep -v "Never logged in"3. 查看歷史登錄用戶以及登錄失敗的用戶 (last 和 lastb 命令) last lastb4. …

使用docker完整搭建前后端分離項目

1、docker的優勢&#xff0c;為啥用docker 2、docker的核心概念 鏡像【Image】- 只讀模板 容器【Container】- 運行鏡像的一個外殼&#xff0c;相當于一個獨立的虛擬機 倉庫【repository】- 鏡像的管理工具&#xff0c;可公開&#xff0c;可私有&#xff1b;類似git倉庫 3、c…

【前端】js通過元素屬性獲取元素

【前端】js通過元素屬性獲取元素 <div for"hc_opportunity_config">aaaaa</div>//通過屬性獲取元素document.querySelector([for"hc_opportunity_config"]) document.querySelector([屬性"屬性值"])

操作教程|通過DataEase開源BI工具對接金山多維表格

前言 金山多維表格是企業數據處理分析經常會用到的一款數據表格工具&#xff0c;它能夠將企業數據以統一的列格式整齊地匯總至其中。DataEase開源數據可視化分析工具可以與金山多維表格對接&#xff0c;方便企業更加快捷地以金山多維表格為數據源&#xff0c;制作出可以實時更…

包拯斷案 | MySQL5.7替換路上踩過的坑 一鍵get解決辦法@還故障一個真相

提問&#xff1a;作為DBA運維的你&#xff0c;是否有過這些煩惱 1、業務系統進行替換投產時&#xff0c;發現數據庫回放并行度低 2、雖然2個數據庫集群使用同一份數據&#xff0c;卻在關閉雙一后&#xff0c;二級從庫的回放效率依舊緩慢&#xff0c;不知是什么原因&#xff1f…

機器人開源項目分享,助力一戶一機器人

最初&#xff0c;因隋煬帝思念心切&#xff0c;命工匠按照柳抃的形象制作了木偶機器人&#xff0c;被認為是歷史上最早的機器人之一。這些木偶機器人通過精巧設計的機關&#xff0c;能夠執行坐、起、拜、伏等動作。 如今&#xff0c;隨著科技的發展&#xff0c;機器人已經廣泛…

從ES5邁向ES6:探索 JavaScript 新增聲明命令與解構賦值的魅力

個人主頁&#xff1a;學習前端的小z 個人專欄&#xff1a;JavaScript 精粹 本專欄旨在分享記錄每日學習的前端知識和學習筆記的歸納總結&#xff0c;歡迎大家在評論區交流討論&#xff01; ES5、ES6介紹 文章目錄 &#x1f4af;聲明命令 let、const&#x1f35f;1 let聲明符&a…

Linux磁盤初始化與fstab文件更新

環境&#xff1a; Redhat 7.9 本文操作&#xff1a; >>給disk設置分區 &#xff08;fdisk&#xff09; >>給disk設置file system格式 (mkfs ) >>創建路徑&#xff0c;并將disk mount上(mkdir和mount ) >>修改fstab文件 初始化Disk 初始化前&#xff…

Vue組件通信 - 組件傳值 / 什么是組件

1.什么是組件通信&#xff1a; 組件&#xff08;.vue&#xff09;通過某種方式來傳遞信息以達到某個目的 2.組件通信可以解決什么問題&#xff1a; 每個組件之間都有獨立的作用域&#xff0c;組件間的數據是無法共享的&#xff0c;但在實際開發中我們常常需要讓組件之間共享…

【計算機網絡原理】對傳輸層TCP協議的重點知識的總結

?????? write in front ??????? ?????????大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之處請多多諒解&#xff0c;讓我們一起共同進步????? . ?? ?xiaoxie?????????—CSDN博客 本文由xiaoxie????????? 原創 CSDN 如…

Spring Bean Map漫游:遍歷背后的生命周期奧秘

1. 引言 在Spring框架中&#xff0c;Bean的生命周期是一個復雜而精妙的過程。其中&#xff0c;遍歷存儲Bean實例的Map&#xff08;通常是DefaultSingletonBeanRegistry中的singletonObjects&#xff09;是這一過程中的重要環節。理解這個遍歷過程以及它在Bean生命周期中的作用…

桌面文件不見了怎么恢復?五種方法解決文件恢復難題,建議收藏

不小心誤刪除了桌面文件&#xff0c;導致文件丟失。事實上誤刪的文件并沒有被永久刪除&#xff0c;而是被移動到了回收站中&#xff0c;可以恢復這些文件。本文將分享多種方法&#xff0c;具體步驟如下。 方法一&#xff1a;從回收站中恢復 大多數操作系統都有回收站或垃圾桶的…

【C語言】結構體內存對齊:熱門面試話題

&#x1f525;引言 書接上文&#xff0c;我們了解關于結構體的基本知識&#xff0c;這篇將深入剖析結構體中一個重要的知識點:內存對齊 關于內存對齊是屬于熱門面試話題&#xff0c;對此單獨放在一篇來分享 &#x1f308;個人主頁&#xff1a;是店小二呀 &#x1f308;C語言筆記…