874 字
4 分鐘

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。驗收時保留空清單、全空槽、混合空槽、無效單筆與正常清單這幾組資料,才看得出數量條件與內容條件是否各自生效。

參考資料:

MDN:Array.prototype.every()

ECMAScript:Array.prototype.every

MDN:Object.hasOwn()

MDN:async function

JavaScript every 空陣列為何是 true?非空清單與空槽驗證
https://laplusda.com/posts/javascript-every-empty-array-validation/
作者
Zero
發佈於
2026-11-05
許可協議
CC BY-NC-SA 4.0