JavaScript every 空陣列為何是 true?非空清單與空槽驗證
驗證於
本文目錄
items.every(isValid) 顯示通過,畫面卻一筆資料都沒有。every 檢查所有被走訪的元素是否符合條件,空陣列沒有反例,所以回傳 true;至少需要一筆資料,是呼叫端要另外加上的條件。
MDN every 文件說明空陣列會回傳 true,也會跳過稀疏陣列的空槽。這會影響「至少一項商品」「至少一位參與者」等表單規則:型別、數量與內容各自通過,才算完成驗證。
length 大於零,仍可能一筆都沒檢查
下面可獨立存成 .mjs,用 Node.js 執行:
import assert from 'node:assert/strict';
let calls = 0;assert.equal([].every(() => { calls += 1; return false; }), true);assert.equal(calls, 0);
const holes = new Array(2);assert.equal(holes.length > 0, true);assert.equal(holes.every(() => { calls += 1; return false; }), true);assert.equal(calls, 0);assert.equal([undefined].every(value => typeof value === 'string'), false);assert.equal(['ok', , 'ready'].every(value => typeof value === 'string'), true);console.log('empty arrays and holes: PASS');new Array(2) 的長度是 2,但索引 0 與 1 尚未持有值;一般陣列的 every 因而沒有走訪任何元素。只有先確定資料是密集陣列,length > 0 && every(...) 才足以表達非空且每筆有效。初始化的差別可參考 new Array 與 Array.from。
API 的 JSON 陣列無法直接表示空槽,前端自己的初始化或 delete 操作則會產生。當驗證函式同時接受兩種來源時,把「索引必須存在」寫進契約比較清楚。
同時要求非空、密集與有效字串
這份 helper 只接受普通資料陣列,限制最多 100 筆、每筆是去除頭尾空白後仍非空的字串。上限 100 是示範的應用政策,可依表單調整;函式只檢查,保留原值與空白。
import assert from 'node:assert/strict';
function isNonEmptyStringList(value) { if (!Array.isArray(value) || value.length === 0 || value.length > 100) { return false; } for (let index = 0; index < value.length; index += 1) { if (!Object.hasOwn(value, index)) return false; const item = value[index]; if (typeof item !== 'string' || item.trim() === '') return false; } return true;}
assert.equal(isNonEmptyStringList(['商品 A', '商品 B']), true);assert.equal(isNonEmptyStringList([' A ']), true);for (const invalid of [null, {}, 'A', [], new Array(2), ['A', , 'B'], [''], [' '], [undefined], [0], Array(101).fill('A')]) { assert.equal(isNonEmptyStringList(invalid), false);}console.log('nonempty dense string list: PASS');用索引迴圈是為了逐一檢查每個位置,包括缺少的索引。Object.hasOwn 明確要求陣列自身持有該索引;本文沒有接受 Proxy、特殊 getter 或在驗證時會變動的物件作為輸入。若下一步要將字串正規化,應另外產生清理後的資料,再依 API 契約提交。
async 驗證要先等結果
every 只判斷 callback 的回傳值是否 truthy。async 函式回傳 Promise,即使 Promise 最後解析為 false,當下也會被視為 truthy。
import assert from 'node:assert/strict';
const ids = ['known', 'missing'];async function exists(id) { return id === 'known'; }
assert.equal(ids.every(async id => exists(id)), true);const results = await Promise.all(ids.map(id => exists(id)));const valid = ids.length > 0 && results.every(result => result === true);assert.equal(valid, false);console.log('await validation results: PASS');這份例子輸入是已確認密集的固定清單,exists 是本機假的非同步查詢。真實服務還要定義查詢失敗時的行為:讓錯誤往外傳並顯示驗證失敗,或用 allSettled區分服務錯誤與資料不符合。把例外一律轉成通過,會使驗證失去作用。
以上三份程式由內容維護流程於 2026-11-05 在 Node.js v24.13.0 執行,未連外查詢或測試表單 UI。驗收時保留空清單、全空槽、混合空槽、無效單筆與正常清單這幾組資料,才看得出數量條件與內容條件是否各自生效。
參考資料: