JavaScriptに論理xorがないのはなぜですか?


回答:


358

JavaScriptは祖先をCまで追跡し、Cには論理XOR演算子がありません。主にそれが役に立たないからです。ビットワイズXORは非常に便利ですが、これまでのプログラミングでは論理XORは必要ありませんでした。

2つのブール変数がある場合は、次のようにしてXORを模倣できます。

if (a != b)

2つの任意の変数を使用!すると、ブール値に強制的に変換してから同じトリックを使用できます。

if (!a != !b)

それはかなりあいまいで、確かにコメントに値するでしょう。確かに、この時点ではビット単位のXOR演算子を使用することもできますが、これは私の好みにはあまりにも賢いでしょう。

if (!a ^ !b)

の唯一の問題は、厳密な不等式演算子であるため!=、と同じことを実行できないことです。a ^= ba !== b
mcpiroman

79

Javascriptにはビット単位のXOR演算子があります:^

var nb = 5^9 // = 12

ブール値と一緒に使用すると、結果は0または1になります(ブール値に変換できますresult = !!(op1 ^ op2))。しかし、Johnが言ったようにresult = (op1 != op2)、これはと同等です。


28
論理的なXORではなく、ビット単位のXORです
Ismail Badawi 2010

66
論理xorとして使用できます。true^true0で、かつfalse^true1です
Pikrass

14
あなたは論理演算子として使用することができ@Pikrass ブール上の他のタイプではなく。||また&&、非ブール値の論理演算子として使用できます(たとえば5 || 7、真の値を"bob" && null返し、偽の値を返します)が^できません。たとえば、5 ^ 72は真です。
マークアメリー

10
@Pikrassしかし、残念なことに、(true ^ false) !== true実際のブール値を必要とするライブラリでは煩わしい
Izkata

2
@Pikrass実装はOSに依存するため、ブール値の論理演算子として使用しないでください。ある種のa ^= trueブール値を切り替えるために使用していたが、電話などの一部のマシンでは失敗する。
Masadow 2015年

30

Javascriptには実際の論理ブール演算子はありません(!かなり接近していますが)。論理演算子はかかるだろうtrueか、falseオペランドとしてのみ返すでしょうtruefalse

JavaScript &&および||あらゆる種類のオペランド取り、あらゆる種類の面白い結果を返します(それらに入力したものは何でも)。

また、論理演算子は常に両方のオペランドの値を考慮する必要があります。

JavaScriptで&&||怠惰なショートカットを取り、んではない特定の場合には第二オペランドを評価し、それによって、その副作用を無視。この動作は、論理XORで再作成することは不可能です。


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')) {

ただし、「論理」xor演算子(^^)は常に両方のオペランドを評価する必要があります。これにより、必要な場合にのみ2番目のオペランドを評価する他の「論理」演算子とは異なります。これが、混乱を避けるために、Javascriptに「論理的な」XORがない理由だと思います。


では、両方のオペランドが偽である場合はどうなりますか?両方とも返される可能性があります。ただし、返却できるのは1つだけです。どれ?最初の1つ?それとも2つ目?私の直感は、最初の、しかし通常「論理的な」演算子は左から右に評価し、最後に評価された値を返すように指示しています。または、両方の値を含む配列ですか?

そして、一方のオペランドが真であり、もう一方のオペランドが偽である場合、xorは真のオペランドを返す必要があります。それとも、前のケースと互換性を持たせるために、真実な配列を含む配列を使用しますか?

そして最後に、両方のオペランドが真実である場合はどうなりますか?あなたは何かおかしいと期待するでしょう。しかし、偽の結果はありません。したがって、操作は何も返しません。だから多分undefinedまたは..空の配列?しかし、空の配列はまだ真実です。

配列アプローチをとると、次のような状態になりif ((a ^^ b).length !== 1) {ます。とても紛らわしい。


どの言語でもXOR / ^^は常に両方に依存するため、常に両方のオペランドを評価する必要があります。AND / &&の場合も同様です。すべてのオペランドが真(JSでは真)でなければならないためです。例外はOR / ||です。真の値が見つかるまで、オペランドを評価するだけだからです。ORリストの最初のオペランドが真である場合、他のどれも評価されません。
パーシー

ただし、JSのXORは、ANDおよびORで規定された規則に違反する必要があるという点で、良い点はあります。実際には、2つのオペランドのいずれかではなく、適切なブール値を返す必要があります。他のものは混乱/複雑さを引き起こす可能性があります。
パーシー、2012年

9
@Percy AND / &&は、最初のオペランドがfalseの場合、2番目のオペランドを評価しません。偽の値が見つかるまでオペランドを評価するだけです。
Robert

@DDS回答を修正していただきありがとうございます。自分で気付かなかった理由に戸惑っています。多分これはパーシーの混乱をある程度説明しています。
ロバート

編集が拒否された後、@ mattsは修正したとおりに再編集したので、(ほぼ)2ポイントを逃しました。3人がそれを拒否し、私は彼らが基準として使用したものに困惑しています。Thxマット。
DDS 2014

16

2つのブール値のXORは、それらが異なるかどうかだけなので、次のようになります。

Boolean(a) !== Boolean(b)


10

ブール値に変換してから、次のようにxorを実行します-

!!a ^ !!b

1
!!a ^ !!bと同等であることに注意してください!a ^ !b。どちらがより読みやすいかについて、議論をすることができます。
tschwab

9

ある...のようなもの:

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

または読みやすい:

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

どうして?知らない。

javascript開発者は、すでに実装されている他の論理演算子で表現できるので、それは不要だと思ったからです。

nandでgonを使用することもできます。これで、他のすべての可能な論理演算を印象付けることができます。

私は個人的に、Cベースの構文言語からの歴史的な理由があると思います。私の知る限りでは、xorが存在しないか、少なくとも非常に珍しいものです。


はい、JavaScriptには3項演算があります。
mwilcox

CとJavaのどちらにも、^(キャレット)文字を使用したXORがあります。
veidelis

7

はい、次のようにしてください。ブールAとBを扱っているとすると、A XOR B値はJavaScriptで次のように計算できます。

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

前の行も次と同等です

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

個人的には、入力する文字数を減らす必要があるため、xor1を好みます。xor1も高速だと思います。2つの計算を実行するだけです。xor2は3つの計算を実行しています。

視覚的な説明...以下の表を読んで(0はfalseを表し、1はtrueを表します)、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     |
------------------------------------------

楽しい。


6
var xor1 = !(a === b);と同じですvar xor1 = a !== b;
daniel1426 2014

この回答は、すべてのデータ型に対して機能するとは限りません(Premchandraの回答のように)。例えば!(2 === 3)ですtrueが、23あるtruthyそう2 XOR 3でなければなりませんfalse
Mariano Desanze 16

2
私のメッセージをもっと注意深く読んだとしたら、私が「ブールAとBを扱っていると仮定して...」と書いたことに気づいたでしょう。
asiby 2016


4

結果の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);


オペランドがまだブール値でない場合、これは失敗します。より良いアイデアはB = ((!state1)!==(!state2))
Doin

正しいですが、型がわからない場合と同じように、オペランドを常に否定してキャストすることができます。B =!!(!state1 ^ !state2); また、括弧が多いのはなぜですか。B = !state1 !== !state2; それともあなたも否定をドロップすることができます:B = state1 !== state2;
ラヨシュMeszaros

括弧はわかりやすくするためのものであり、コードを記述するときに演算子の優先順位に関するドキュメントを確認する必要もありません。;-)最後の式は私の以前の不満に悩まされています:オペランドがブール値でないと失敗します。しかし、そうであることが確かであれば、それは間違いなく最も単純で最速の「logical xor」式です。
Doin

最後の式でを意味する場合は、ビット単位ではなく論理演算子であるため、state1 !== state2そこでキャストする必要はありません!==12 !== 4本当'xy' !== trueですまた本当です の!=代わりに使用する場合は!==、キャストを行う必要があります。
Lajos Meszaros

1
両方の結果!==とは!=常にブール...あなたが作っているの区別は絶対的に問題ではないこと、があることが想定されていないことを確認するものです。問題は、我々はXOR演算子であることを望むが、本当に表現です(Boolean(state1) !== Boolean(state2))。ブール値の場合、「xy」、true 12、4 およびはすべて真の値であり、に変換する必要がありtrueます。そうする("xy" XOR true)必要がありますがfalse、あなたが指摘するように("xy" !== true)代わりtrueにです。つまり!==、適用する前に引数をブール値変換した場合に限り、!=(どちらも)「論理XOR」同等になります。
Doin

2

上記のxor関数では、論理xorが厳密に論理xorではないため、類似した結果になります。つまり、データ型の一致を考慮して、等しい値の場合はfalse」「異なる値の場合はtrue 」になります

このXOR関数は、実際のXORまたは論理演算子として動作します、それは渡す値にtrueまたはfalse応じてつながる手段があり、truthyまたはfalsy。ニーズに合わせてご利用ください

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

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

「xnor」は「===」と同じです。
daniel1426 2014

@ daniel1426よくありません。と同じ(!!x) === (!!y)です。違いはブール値へのキャストです。'' === 0は偽であり、xnor('', 0)真は真です。
tschwab

2

Typescript(+は数値に変わります):

value : number = (+false ^ +true)

そう:

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

通常のJavaScriptでは@Sheraffが!!(false ^ true)ブール値で正常に機能します。typescriptでは、有効にするために+が必要です!!(+false ^ +true)
pfg

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])}`)
}


0

論理XOR(^^)がない理由は、&&および||とは異なります。遅延論理的な利点はありません。それが評価されなければならない右と左の両方の式の状態です。


0

2つ以上の変数で機能し、ボーナスとしてカウントを提供する代替ソリューションを次に示します。

標準のIFステートメントに演算子があるかのように、真偽値の論理XORをシミュレートするためのより一般的なソリューションを次に示します。

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!` );

私がこれを好きな理由は、「これらの変数のうちいくつが真実であるか」にも答えるため、通常はその結果を事前に保存します。

そして、厳密なブール値-TRUEのxorチェック動作を必要とする人は、次のようにします。

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

カウントを気にしない場合、または最適なパフォーマンスを気にする場合:真偽のソリューションでは、ブール値に強制変換された値にビット単位のxorを使用します。

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

0

JavaScriptとTypeScriptでXORを作成するためのこのソリューションを見つけました。

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
}

-2

これを短く理解しやすいものにしてください

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

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

これはどのデータ型でも機能します


3
これは、すべてのデータ型に対して機能するわけではありません。論理型強制演算子と同様に、 "foo" xorまたは "bar"はfalseであると予想します。どちらも真実であるためです。現在のところ、関数には当てはまりません。一般に、実行するtrue == someboolean必要はないので、実際には、厳密に等しくないものを関数にラップしています。
Gijs 2013

Hi GiJs、私はあなたの主張に同意します。「foo」と「bar」は真実の値です。しかし、xorと同様の出力が得られる(等しくない値はtrueになり、等しい値はfalseになる)ことを念頭に置いて関数を記述します。そして、私はそのようなシナリオでより多くの使用法を見つけました。しかし、私は以下の別の答えで真の論理的xorを書いています。
Premchandra Singh 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.