JavaScript에 논리적 xor가없는 이유는 무엇입니까?


답변:


358

JavaScript는 조상을 다시 C로 추적하며 C에는 논리적 XOR 연산자가 없습니다. 주로 유용하지 않기 때문에. Bitwise XOR은 매우 유용하지만 수년간의 프로그래밍에서 논리적 XOR이 필요하지 않았습니다.

부울 변수가 두 개인 경우 다음을 사용하여 XOR을 모방 할 수 있습니다.

if (a != b)

두 개의 임의 변수를 사용하면 변수 !를 부울 값으로 강제 변환하고 동일한 트릭을 사용할 수 있습니다.

if (!a != !b)

그래도 꽤 모호하며 분명히 의견이 필요합니다. 실제로이 시점에서 비트 XOR 연산자를 사용할 수도 있지만 내 취향에는 너무 영리합니다.

if (!a ^ !b)

유일한 불평등 문제 는 엄격한 불평등 연산자 이기 때문에과!= 동일하게 수행 할 수 없다는 것 입니다. a ^= ba !== b
mcpiroman

79

자바 스크립트에는 비트 XOR 연산자가 있습니다 : ^

var nb = 5^9 // = 12

부울과 함께 사용할 수 있으며 결과를 0 또는 1로 제공합니다 (예를 들어 부울로 다시 변환 할 수 있음 result = !!(op1 ^ op2)). 그러나 John이 말했듯이 result = (op1 != op2)이는보다 명확합니다.


28
논리적 인 XOR이 아닌 비트 XOR
Ismail Badawi

66
논리 xor로 사용할 수 있습니다. true^true0, false^true1입니다.
Pikrass

14
@Pikrass 부울 에서는 논리 연산자로 사용할 수 있지만 다른 유형에서는 사용할 수 없습니다. ||&&비 논리 값에 논리 연산자로 사용 (예 : 수 5 || 7하는 truthy 값을 반환 "bob" && nullfalsey 값을 반환)하지만 ^할 수 없습니다. 예를 들어, 5 ^ 72는 진실입니다.
Mark Amery

10
@Pikrass 그러나 슬프게도 (true ^ false) !== true실제 부울을 필요로하는 라이브러리를 사용하면 성
가실 수 있습니다

2
@Pikrass 구현은 OS에 따라 다르므로 부울의 논리 연산자로 사용해서는 안됩니다. a ^= true부울을 전환하기 위해 일종의를 사용하고 있었고 전화와 같은 일부 컴퓨터에서는 실패합니다.
Masadow 2016 년

30

Javascript에는 실제 논리 부울 연산자가 없습니다 ( !아주 가깝습니다). 논리 연산자는 걸릴 것 true또는 false피연산자 만 반환 true또는 false.

자바 스크립트 &&||피연산자의 모든 종류를 가지고 (당신이 그들로 공급 무엇이든) 재미 결과의 모든 종류를 반환합니다.

또한 논리 연산자는 항상 두 피연산자의 값을 고려해야합니다.

자바 스크립트 &&||게으른 바로 가기를 가지고 할 수 없습니다 어떤 경우함으로써 부작용 방치 두 번째 피연산자를 평가합니다. 이 동작은 논리 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 연산자 ( ^^)는 항상 두 피연산자를 모두 평가해야합니다. 이것은 필요한 경우에만 두 번째 피연산자를 평가하는 다른 "논리적"연산자와는 다릅니다. 혼동을 피하기 위해 이것이 자바 스크립트에 "논리적"xor가없는 이유라고 생각합니다.


두 피연산자가 모두 잘못된 경우 어떻게됩니까? 둘 다 반환 될 수 있습니다. 그러나 하나만 반환 할 수 있습니다. 어느 것? 첫번째? 아니면 두 번째? 내 직감은 첫 번째이지만 일반적으로 "논리적"연산자는 왼쪽에서 오른쪽으로 평가하고 마지막으로 평가 된 값을 반환하도록 지시합니다. 아니면 두 값을 모두 포함하는 배열입니까?

그리고 한 피연산자가 진실이고 다른 피연산자가 거짓이면, xor는 진실한 피연산자를 반환해야합니다. 아니면 이전 사례와 호환되도록 진실한 배열을 포함하는 배열입니까?

마지막으로 두 피연산자가 모두 진실이라면 어떻게됩니까? 당신은 뭔가 잘못된 것을 기대할 것입니다. 그러나 허위 결과는 없습니다. 따라서 작업이 아무것도 반환해서는 안됩니다. 아마도 undefined또는 .. 빈 배열입니까? 그러나 빈 배열은 여전히 ​​진실입니다.

배열 접근 방식을 사용하면 다음과 같은 조건으로 끝납니다 if ((a ^^ b).length !== 1) {. 매우 혼란 스럽습니다.


모든 언어의 XOR / ^^은 항상 두 피연산자 모두에 의존하므로 두 피연산자를 모두 평가해야합니다. 모든 피연산자가 true (Justy에서 JS) 리턴 패스 여야하므로 AND / &&도 마찬가지입니다. 예외는 OR / || 진실한 값을 찾을 때까지 피연산자 만 평가해야하기 때문입니다. OR 목록의 첫 번째 피연산자가 진실이면 다른 것들은 평가되지 않습니다.
Percy

그러나 JS의 XOR이 AND 및 OR에 의해 설정된 규칙을 위반해야한다는 점을 잘 알고 있습니다. 실제로 두 피연산자 중 하나가 아닌 적절한 부울 값을 반환해야합니다. 다른 어떤 것도 혼란 / 복잡함을 유발할 수 있습니다.
Percy

9
@Percy AND / &&는 첫 번째 피연산자가 false 인 경우 두 번째 피연산자를 평가하지 않습니다. 거짓 값을 찾을 때까지 피연산자 만 평가합니다.
Robert

@DDS 답변을 수정 해 주셔서 감사합니다. 왜 내가 스스로 눈치 채지 못했는지 의아해합니다. 아마도 이것은 퍼시의 혼란을 어느 정도 설명 할 수있을 것입니다.
Robert

내 편집이 거부 된 후 @matts가 수정 한대로 정확하게 다시 편집 했으므로 (아마도) 2 점을 놓쳤습니다. 3 명이 그것을 거부했고 나는 그들이 기준으로 사용한 것을 당황했습니다. Thx 매트.
DDS

16

두 부울의 XOR은 단순히 서로 다른지 여부입니다.

Boolean(a) !== Boolean(b)

12

값을 부울 형식으로 변환 한 다음 비트 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 ) ) {
  ...
}

왜? 던노

자바 스크립트 개발자는 이미 구현 된 다른 논리 연산자로 표현할 수 있으므로 불필요하다고 생각했기 때문입니다.

당신은 낸드와 곤두박질을 할 수 있으며, 그로부터 가능한 모든 다른 논리 연산에 깊은 인상을 줄 수 있습니다.

개인적으로 c 기반 구문 언어를 사용하는 역사적인 이유가 있다고 생각합니다. 제 지식이 없거나 적어도 매우 드문 곳입니다.


예, 자바 스크립트에는 삼항 연산이 있습니다.
mwilcox

C와 Java는 모두 ^ (캐럿) 문자를 사용하여 XOR을 갖습니다.
veidelis

7

예, 다음을 수행하십시오. 부울 A 및 B를 처리한다고 가정하면 다음을 사용하여 JavaScript에서 A XOR B 값을 계산할 수 있습니다

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

이전 줄은 다음과 같습니다.

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

개인적으로 문자를 적게 입력해야하기 때문에 xor1을 선호합니다. xor1도 더 빠르다고 생각합니다. 두 가지 계산을 수행하고 있습니다. xor2는 세 가지 계산을 수행합니다.

시각적 설명 ... 다음 표 (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

이 답변은 Premchandra의 답변과 같은 모든 데이터 유형에 적용되지 않습니다. 예를 들면 !(2 === 3)이다 true, 그러나 2하고 3있습니다 truthy 그렇게 2 XOR 3해야한다 false.
마리아노 데 산제

2
내 메시지를 더주의 깊게 읽으면 "부울 A와 B를 처리한다고 가정하고 ..."라고 쓴 것을 알았을 것입니다.
asiby


4

결과를 int 를 이중 부정 으로 부울 로 변환하는 것은 어떻습니까? 그렇게 예쁘지는 않지만 실제로는 컴팩트합니다.

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;
라요스 메스 자 로스

괄호는 명확성을 기하기 때문에 코드를 작성할 때 연산자 우선 순위에 대한 문서를 확인할 필요가 없습니다! ;-) 마지막 표현이 이전 불만으로 고통받습니다. 피연산자가 부울이 아닌 경우 실패합니다. 그러나 그들이 확실하다면, 그것은 가장 단순하고 가장 빠른 "논리적 xor"표현입니다.
Doin

마지막 표현으로 의미 하는 경우 비트 단위가 아닌 논리 연산자 state1 !== state2이므로 캐스팅을 수행 할 필요가 없습니다 !==. 12 !== 4사실 'xy' !== true이기도합니다. !=대신에 사용하려면 !==캐스팅해야합니다.
Lajos Meszaros

1
모두의 결과 !==와는 !=항상 부울 ... 당신이 만들고있어 구별이 절대적으로 문제가 아니에요 그,있을 예정이다하지 않도록 것입니다. 문제는 우리가 원하는 XOR 연산자 가 실제로 표현식이라는 것 (Boolean(state1) !== Boolean(state2))입니다. 부울의 경우 "xy", 12, 4이며 true 모두 진솔한 값이며로 변환해야합니다 true. 당신이 지적한대로 그렇게 ("xy" XOR true)해야 false하지만 ("xy" !== true)대신 true에 있습니다. 그래서 !==!=있다 "논리적 인 XOR"을 (모두) 해당하는 경우에만, 당신이 논리 값에 해당 인수를 변환 하기 전에 적용.
Doin

2

위의 xor 함수 에서 논리 xor는 정확히 논리 xor가 아니기 때문에 SIMILAR 결과가 나옵니다. 즉, 데이터 유형 일치를 고려하여 " 동일한 값에 대해서는 거짓""다른 값에 대해서는 참" 을 의미합니다.

이 XOR 기능은 실제 또는 XOR 논리 연산자로 작동 , 통과 값은하기가 참 또는 거짓 결과있어서 의미 truthy 또는 falsy . 필요에 따라 사용하십시오

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

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

"xnor"는 "==="과 같습니다.
daniel1426

@ daniel1426은 아닙니다. 와 동일합니다 (!!x) === (!!y). 차이점은 부울로 변환 된 것입니다. 사실이지만 '' === 0거짓 xnor('', 0)입니다.
tschwab

2

Typescript에서 (+는 숫자 값으로 변경됨) :

value : number = (+false ^ +true)

그래서:

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

정상적인 자바 스크립트의 @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"는 모두 거짓이기 때문에 두 가지 모두 사실이기 때문입니다. 현재 귀하의 기능에는 해당되지 않습니다. 일반적으로 수행 true == someboolean할 필요는 없으므로 실제로 수행 한 작업은 엄격한 같지 않음을 함수로 래핑하는 것입니다.
Gijs

안녕하세요 GiJs, 나는 "foo"와 "bar"가 진실한 가치라는 당신의 주장에 동의합니다. 그러나 나는 xor와 비슷한 출력을 얻을 것이라는 점을 명심하고 함수는 동일하지 않습니다 (동일한 값은 참, 동일한 값은 거짓). 그리고 나는 그러한 시나리오에서 더 많은 사용법을 발견했습니다. 그러나 아래의 또 다른 대답으로 진정한 논리 xor를 작성하고 있습니다.
Premchandra Singh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.