從笛摩根定律看 JavaScript:兩行看似不同的程式碼邏輯相等 feat:some 和 every
程式碼比較
在 JavaScript 中,經常需要判斷一個陣列(targetArray
)中的元素,是否都存在於另一個陣列(baseArray
)當中。常見的做法有兩種寫法:
// 寫法 A:只要 targetArray 中「有一個」元素不在 baseArray 中就回傳 true
targetArray.some(item => !baseArray.includes(item));
// 寫法 B:「並非」targetArray 的「每個」元素都出現在 baseArray
!targetArray.every(item => baseArray.includes(item));
乍看之下,這兩段邏輯可能會讓人猶豫一下,但結論非常明確:
這兩段程式碼的邏輯是完全等價的。
為什麼這兩段邏輯等價?
從數學邏輯的角度來說,這兩個敘述分別對應以下形式:
- 寫法 A:存在某個元素 (
∃x
),這個元素不滿足某條件 (¬P(x)
)。 - 寫法 B:並非每個元素 (
¬∀x
) 都滿足某條件 (P(x)
)。
透過數學邏輯的觀點,我們可以更清楚地理解為什麼這兩段程式碼會完全一致。
數學邏輯推導
要理解這種等價,關鍵在於德摩根定律(De Morgan’s Law)。讓我們從最基本的命題邏輯開始:
說明 | 公式 |
---|---|
否定「A 且 B」 =「否定 A 或 否定 B」 | ¬(A ∧ B) ⇔ (¬A ∨ ¬B) |
否定「A 或 B」 =「否定 A 且 否定 B」 | ¬(A ∨ B) ⇔ (¬A ∧ ¬B) |
將這個概念延伸至無限多個元素的情況:
∀x P(x)
表示每個元素都滿足條件 P,類似於無限個 AND。∃x ¬P(x)
表示存在某個元素不滿足條件 P,類似於無限個 OR。
因此我們有:
¬∀x P(x) ⇔ ∃x ¬P(x)