簡體   English   中英

為什么沒有邏輯異或?

[英]Why is there no logical XOR?

為什么JavaScript沒有邏輯XOR或?

JavaScript 將其祖先追溯到 C,而 C 沒有邏輯 XOR 運算符。 主要是沒用。 按位異或非常有用,但在我多年的編程生涯中,我從來不需要邏輯異或。

如果你有兩個布爾變量,你可以模擬異或:

if (a != b)

使用兩個任意變量,您可以使用! 將它們強制為布爾值,然后使用相同的技巧:

if (!a != !b)

雖然這很晦澀,但肯定值得評論。 實際上,此時您甚至可以使用按位 XOR 運算符,盡管這對我來說太聰明了:

if (!a ^ !b)

Javascript 有一個按位異或運算符:^

var nb = 5^9 // = 12

您可以將它與布爾值一起使用,它會將結果作為 0 或 1(您可以將其轉換回布爾值,例如result = !!(op1 ^ op2) )。 但正如約翰所說,它相當於result = (op1 != op2) ,更清楚。

Javascript 中沒有真正的邏輯布爾運算符(盡管!非常接近)。 邏輯運算符只會將truefalse作為操作數,並且只會返回truefalse

在 Javascript &&||采用各種操作數並返回各種有趣的結果(無論您輸入什么)。

此外,邏輯運算符應始終考慮兩個操作數的值。

在 Javascript &&||采取懶惰的捷徑,在某些情況下評估第二個操作數,從而忽略其副作用。 使用邏輯異或無法重新創建此行為。


a() && b()評估a()並返回結果(如果它是假的)。 否則它計算b()並返回結果。 因此,如果兩個結果都為真,則返回的結果為真,否則為假。

a() || b() a() || b()評估a()並返回結果(如果為真)。 否則它計算b()並返回結果。 因此,如果兩個結果均為假,則返回的結果為假,否則為真。

所以一般的想法是先評估左操作數。 正確的操作數只有在必要時才會被評估。 最后一個值就是結果。 這個結果可以是任何東西。 對象、數字、字符串……隨便什么!

這使得編寫類似的東西成為可能

image = image || new Image(); // default to a new Image

要么

src = image && image.src; // only read out src if we have an image

但是這個結果的真值也可以用來決定一個“真正的”邏輯運算符是否會返回 true 或 false。

這使得編寫類似的東西成為可能

if (typeof image.hasAttribute === 'function' && image.hasAttribute('src')) {

要么

if (image.hasAttribute('alt') || image.hasAttribute('title')) {

但是“邏輯”異或運算符 ( ^^ ) 總是必須評估兩個操作數。 這使得它不同於僅在必要時才評估第二個操作數的其他“邏輯”運算符。 我認為這就是為什么在 Javascript 中沒有“邏輯”異或,以避免混淆。


那么如果兩個操作數都是假的,會發生什么? 兩者都可以退貨。 但是只能退一個。 哪一個? 第一個? 還是第二個? 我的直覺告訴我返回第一個但通常是“邏輯”運算符從左到右評估並返回最后評估的值。 或者可能是一個包含這兩個值的數組?

如果一個操作數為真而另一個操作數為假,則異或應返回真值。 或者可能是一個包含真實數組的數組,以使其與前一種情況兼容?

最后,如果兩個操作數都為真,會發生什么? 你會期待一些虛假的東西。 但是沒有錯誤的結果。 所以這個操作不應該返回任何東西。 所以也許undefined或.. 一個空數組? 但是空數組仍然是真實的。

采用數組方法,您最終會遇到類似if ((a ^^ b).length !== 1) {的條件。 非常混亂。

兩個布爾值的異或只是它們是否不同,因此:

Boolean(a) !== Boolean(b)

將值轉換為布爾形式,然后進行按位異或

Boolean(a) ^ Boolean(b) // === 0 | 1

請注意,此表達式的結果是一個數字不是布爾值。

按位異或也適用於非布爾值,但請記住這是一個按位運算符,而不是邏輯運算符。 使用非布爾值可能不會像您最初預期的那樣:

(5 ^ 3) === 6 // true

隱蔽為布爾值,然后像執行 xor -

!!a ^ !!b

有...有點:

if( foo ? !bar : bar ) {
  ...
}

或者更容易閱讀:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}

為什么? 不知道。

因為 javascript 開發人員認為這是不必要的,因為它可以由其他已經實現的邏輯運算符表示。

您也可以只使用 nand 和僅此而已,您可以從中給所有其他可能的邏輯操作留下深刻印象。

我個人認為它有歷史原因驅動基於 c 的語法語言,據我所知 xor 不存在或至少不常見。

是的,只需執行以下操作。 假設您正在處理布爾值 A 和 B,那么可以使用以下代碼在 JavaScript 中計算 A XOR B 值

var xor1 = !(a === b);

上一行也等同於以下

var xor2 = (!a !== !b);

就個人而言,我更喜歡 xor1,因為我需要輸入的字符更少。 我相信 xor1 也更快。 它只是執行兩個計算。 xor2 正在執行三個計算。

視覺解釋...閱讀下表(其中 0 代表錯誤,1 代表正確)並比較第 3 列和第 5 列。

:(A === B):

| A | B | A XOR B | A === B | !(A === B) |
------------------------------------------
| 0 | 0 |    0    |    1    |      0     |
| 0 | 1 |    1    |    0    |      1     |
| 1 | 0 |    1    |    0    |      1     |
| 1 | 1 |    0    |    1    |      0     |
------------------------------------------

享受。

查看:

你可以像這樣模仿它:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}

如何將結果int轉換為帶有雙重否定的bool 不是很漂亮,但真的很緊湊。

 var state1 = false, state2 = true; var A = state1 ^ state2; // will become 1 var B =;.(state1 ^ state2); // will become true console.log(A); console.log(B);

為了后代的利益,並且因為我發現這是一個很好的練習,您可以很容易地利用 XOR 運算符的真實性來強制執行。 就像選擇的答案一樣,它可能有點太聰明了。

const xor = (a, b) => !!(!!a ^ !!b)

console.log(undefined ^ {}) // Returns 0, bitwise can't be done here.
console.log(xor(undefined, {})) // Returns true, because {} is truthy and undefined is falsy
console.log(0 ^ 1) // Works naturally, returns 1
console.log(xor(0, 1)) // Also works, returns true
console.log(true ^ false) // Again, returns true
console.log(xor(true, false)) // And again, returns true...

為了好玩,這應該在 TypeScript 中工作,通過強制顯式 any:

const xor = (a: any, b: any) => !!((!!a as any) ^ (!!b as any))

布爾值的一種襯墊:

if (x ? !y : y) { do something cool }

在上面的異或函數中,它會產生類似的結果,因為邏輯異或不完全是邏輯異或,這意味着它將產生“相等值為假”“不同值為真”並考慮數據類型匹配。

這個 xor 函數將作為實際的 xor 或邏輯運算符工作,這意味着它會根據傳遞的值是truthy還是falsy來產生 true 或 false 。 根據您的需要使用

function xor(x,y){return true==(!!x!==!!y);}

function xnor(x,y){return !xor(x,y);}

沒有邏輯 XOR (^^) 的原因是因為不像 && 和 || 它不會提供任何惰性邏輯優勢。 也就是說,必須評估左右兩個表達式的狀態。

在 Typescript 中(+ 變為數值):

value : number = (+false ^ +true)

所以:

value : boolean = (+false ^ +true) == 1

cond1 xor cond2等同於cond1 + cond 2 == 1

這是證明:

 let ops = [[false, false],[false, true], [true, false], [true, true]]; function xor(cond1, cond2){ return cond1 + cond2 == 1; } for(op of ops){ console.log(`${op[0]} xor ${op[1]} is ${xor(op[0], op[1])}`) }

這是一個替代解決方案,適用於 2+ 個變量並提供計數作為獎勵。

這是一個更通用的解決方案,可以為任何真值/假值模擬邏輯異或,就像您在標准 IF 語句中使用運算符一樣:

 const v1 = true; const v2 = -1; // truthy (warning, as always) const v3 = ""; // falsy const v4 = 783; // truthy const v5 = false; if( (.;v1 +.;v2 + !!v3 + !!v4 + !!v5 ) === 1 ) document.write( `[ ${v1} XOR ${v2} XOR "${v3}" XOR ${v4} XOR ${v5} ] is TRUE!` ); else document.write( `[ ${v1} XOR ${v2} XOR "${v3}" XOR ${v4} XOR ${v5} ] is FALSE!` );

我喜歡這個的原因是因為它還回答了“這些變量中有多少是真實的?”,所以我通常會預先存儲那個結果。

對於那些想要嚴格的 boolean-TRUE 異或檢查行為的人,只需執行以下操作:

if( ( ( v1===true ) + ( v2===true ) + ( v3===true ) + ( v4===true ) + ( v5===true ) ) === 1 )
  // etc.

如果您不關心計數,或者您關心最佳性能:那么只需對強制為布爾值的值使用按位異或,以獲得真/假解決方案:

if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
  // etc.

嘿,我找到了這個解決方案,可以在 JavaScript 和 TypeScript 上進行異或運算。

if( +!!a ^ +!!b )
{
  //This happens only when a is true and b is false or a is false and b is true.
}
else
{
  //This happens only when a is true and b is true or a is false and b is false
}

這里提出的大多數方法都很難閱讀和理解。 與其編寫一些神秘而神奇的比較或試圖評論它們,不如定義一個不言自明的可重用 function :

function either(a: boolean, b: boolean): boolean {
  return (a !== b);
}

或者更通用的:

function either(a: any, b: any): boolean {
  return Boolean(a) !== Boolean(b);
}

然后你可以像這樣使用它:

assert(either(one, another), 'Either one or another, not both');

試試這個簡短易懂的

function xor(x,y){return true==(x!==y);}

function xnor(x,y){return !xor(x,y);}

這適用於任何數據類型

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM