Neden JavaScript'te mantıksal xor yok?


Yanıtlar:


358

JavaScript, atalarını C'ye kadar izler ve C'nin mantıksal bir XOR operatörü yoktur. Temelde yararlı olmadığı için. Bitwise XOR son derece yararlıdır, ancak tüm programlama yıllarımda hiçbir zaman mantıklı bir XOR'a ihtiyaç duymadım.

İki boolean değişkeniniz varsa XOR'u aşağıdakilerle taklit edebilirsiniz:

if (a != b)

İki rasgele değişkenle, !bunları boole değerlerine zorlamak ve sonra aynı hileyi kullanmak için kullanabilirsiniz:

if (!a != !b)

Bu oldukça belirsiz ve kesinlikle bir yorumu hak ediyor. Aslında, bu noktada bitsel XOR operatörünü bile kullanabilirsiniz, ancak bu benim zevkime göre çok zekice olurdu:

if (!a ^ !b)

Tek sorun !=aynı şeyi yapamayacağınızdır a ^= b, çünkü a !== bsadece katı eşitsizlik operatörüdür.
mcpiroman

79

Javascript'te bitsel bir XOR operatörü var: ^

var nb = 5^9 // = 12

Booleans ile kullanabilirsiniz ve sonucu 0 veya 1 olarak verir (boolean'a dönüştürebilirsiniz, örneğin result = !!(op1 ^ op2)). Ama John'un dediği gibi, bu result = (op1 != op2)daha açıktır.


28
Bu bitsel XOR, mantıksal değil XOR
Ismail Badawi

66
Mantıksal bir x veya olarak kullanabilirsiniz. true^true0 ve false^true1'dir.
Pikrass

14
@Pikrass Booleans üzerinde mantıksal bir operatör olarak kullanabilirsiniz , ancak diğer türlerde kullanamazsınız. ||ve boolean &&olmayanlar üzerinde mantıksal işleçler olarak kullanılabilir (örn. 5 || 7doğru bir değer döndürür, bir falsey değeri "bob" && nulldöndürür), ancak ^kullanılamaz. Örneğin 5 ^ 7, doğru olan 2'ye eşittir.
Mark Amery

10
@Pikrass Ama ne yazık ki, (true ^ false) !== truebu gerçek booleans gerektiren kütüphaneler ile sinir bozucu
Izkata

2
@Pikrass Uygulama işletim sistemine bağlı olduğundan asla boolean üzerinde mantıksal bir operatör olarak kullanmamalısınız. Ben a ^= truebooleans geçiş yapmak için bir tür kullanıyordum ve telefon gibi bazı makinelerde başarısız.
Masadow

30

Javascript'te gerçek bir mantıksal boolean operatörü yoktur ( !oldukça yakın olmasına rağmen ). Mantıksal bir işleç yalnızca trueveya falseişlenen olarak alınır ve yalnızca trueveya döndürür false.

Javascript &&ve ||her türlü işlenen almak ve her türlü komik sonuçları (ne beslerseniz onlara) döndürün.

Ayrıca mantıksal bir operatör her zaman her iki işlenenin de değerini dikkate almalıdır.

JavaScript &&ve ||tembel bir kısayol alıp do not bazı durumlarda ve böylece yan etkilerin ihmal ikinci işlenen değerlendirir. Bu davranışın mantıksal bir xor ile yeniden oluşturulması imkansızdır.


a() && b()a()sonuç yanlışsa değerlendirir ve döndürür. Aksi takdirde b()sonucu değerlendirir ve döndürür. Bu nedenle, her iki sonuç da doğruysa döndürülen sonuç doğrudur ve aksi takdirde yanlıştır.

a() || b()a()doğruysa sonucu değerlendirir ve döndürür. Aksi takdirde b()sonucu değerlendirir ve döndürür. Bu nedenle, her iki sonuç da falsiyse döndürülen sonuç yanlıştır ve aksi takdirde doğrudur.

Genel fikir ilk önce sol operandı değerlendirmektir. Doğru işlenen yalnızca gerektiğinde değerlendirilir. Ve son değer sonuçtur. Bu sonuç herhangi bir şey olabilir. Nesneler, sayılar, teller .. her neyse!

Bu gibi şeyler yazmayı mümkün kılar

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

veya

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

Ancak bu sonucun gerçek değeri, "gerçek" bir mantıksal operatörün doğru mu yanlış mı döneceğine karar vermek için de kullanılabilir.

Bu gibi şeyler yazmayı mümkün kılar

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

veya

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

Ancak bir "mantıksal" xor operatörü ( ^^) her zaman her iki işleneni de değerlendirmek zorundadır. Bu, yalnızca gerektiğinde ikinci işleneni değerlendiren diğer "mantıksal" operatörlerden farklı kılar. Ben karışıklık önlemek için bu yüzden Javascript hiçbir "mantıksal" xor olduğunu düşünüyorum.


Peki her iki işlenen de falsiyse ne olmalı? Her ikisi de iade edilebilir. Ancak sadece bir tanesi iade edilebilir. Hangisi? İlki? Yoksa ikincisi mi? Sezgim bana ilk fakat genellikle "mantıksal" operatörleri soldan sağa döndürüp son değerlendirilen değeri döndürmemi söylüyor. Ya da belki her iki değeri içeren bir dizi?

Ve eğer bir işlenen doğruysa ve diğer işlenen yanlışsa, bir xor doğru olanı döndürmelidir. Ya da önceki durumla uyumlu hale getirmek için doğruyu içeren bir dizi?

Ve son olarak, her iki işlenen de doğruysa ne olmalı? Yanlış bir şey beklersiniz. Ancak hiçbir yanlış sonuç yoktur. Yani operasyon hiçbir şey döndürmemeli. Belki de undefined.. boş bir dizi mi? Ancak boş bir dizi hala doğrudur.

Dizi yaklaşımını kullanmak gibi koşullarla sonuçlanır if ((a ^^ b).length !== 1) {. Çok kafa karıştırıcı.


Herhangi bir dilde XOR / ^^ her zaman her iki işleneni de değerlendirmek zorundadır, çünkü her zaman her ikisine de bağımlıdır. Aynı şey AND / && için de geçerlidir, çünkü tüm işlenenler doğru olmalıdır (JS'de doğruluk) dönüş kartı. İstisna OR / || çünkü işlenenleri yalnızca doğru bir değer bulana kadar değerlendirmelidir. Bir OR listesindeki ilk işlenen doğruysa, diğer hiçbiri değerlendirilmez.
Percy

Bununla birlikte, JS'deki XOR'un AND ve OR tarafından ortaya konan konvansiyonu kırması gerektiği konusunda iyi bir noktaya değiniyorsunuz. Aslında iki işlenenden biri yerine uygun bir boole değeri döndürmek zorunda kalacaktı. Başka herhangi bir şey karışıklığa / karmaşıklığa neden olabilir.
Percy

9
@Percy AND / &&, ilk işlenen yanlışsa ikinci işleneni değerlendirmez. Yalnızca işlenenleri bir falsy değeri bulana kadar değerlendirir.
Robert

@DDS Cevabı düzelttiğiniz için teşekkür ederiz. Neden kendim fark etmediğime şaşkınım. Belki bu Percy'nin karışıklığını bir dereceye kadar açıklar.
Robert

Düzenlemem reddedildi, daha sonra @matts tam olarak düzelttiğim şekilde yeniden düzenledi, bu yüzden (yetersiz) 2 puanımı kaçırdım. 3 kişi bunu reddetti ve kriter olarak kullandıkları şeyi şaşırttı. Teşekkürler.
DDS

16

İki booleanın XOR'u, farklı olmalarıdır, bu nedenle:

Boolean(a) !== Boolean(b)

12

Değerleri Boole formuna dönüştürün ve bitsel XOR alın. Boole olmayan değerlere de yardımcı olacaktır.

Boolean(a) ^ Boolean(b)

10

Boole'ye dönüştürün ve sonra xveya gibi gerçekleştirin -

!!a ^ !!b

1
!!a ^ !!bEşdeğer olduğunu unutmayın !a ^ !b. Okunması daha kolay olan argümanlar yapılabilir.
tschwab

9

orada ... bir çeşit:

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

veya daha kolay okunabilir:

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

neden? Bilmiyorum.

çünkü javascript geliştiricileri, zaten uygulanmış olan diğer mantıksal operatörler tarafından ifade edilebileceğinden bunun gereksiz olacağını düşündüler.

sadece nand ile de olabilir ve bu, bundan mümkün olan diğer tüm mantıksal işlemleri etkileyebilirsiniz.

kişisel olarak, bence xor'un mevcut olmadığı veya en azından son derece nadir olduğu, c-tabanlı sözdizimi dillerinden gelen tarihsel nedenlere sahip olduğunu düşünüyorum.


Evet, javascript üçlü ops var.
mwilcox

Hem C hem de Java, ^ (düzeltme) karakterini kullanarak XOR'a sahiptir.
veidelis

7

Evet, sadece aşağıdakileri yapın. Booleans A ve B ile uğraştığınızı varsayarsak, bir XOR B değeri JavaScript'te aşağıdakiler kullanılarak hesaplanabilir

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

Önceki satır ayrıca aşağıdakine eşdeğerdir:

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

Şahsen, daha az karakter yazmam gerektiğinden xor1'i tercih ediyorum. Xor1'in de daha hızlı olduğuna inanıyorum. Sadece iki hesaplama yapıyor. xor2 üç hesaplama yapıyor.

Görsel Açıklama ... Aşağıdaki tabloyu okuyun (burada 0 değeri yanlış, 1 değeri doğru anlamına gelir) ve 3. ve 5. sütunları karşılaştırın.

! (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     |
------------------------------------------

Zevk almak.


6
var xor1 = !(a === b);ile aynıvar xor1 = a !== b;
daniel1426

Bu cevap tüm veri türleri için geçerli değildir (Premchandra'nın yanıtı gibi). mesela !(2 === 3)olduğunu true, ancak 2ve 3vardır truthy böylece 2 XOR 3olmalıdır false.
Mariano Desanze

2
Mesajımı daha dikkatli okumuş olsaydın, "A ve B booleleriyle uğraştığınızı varsayarak ..." yazdığımı fark ederdin.
asiby


4

Sonuç int değerini çift ​​olumsuzlama içeren bir boole dönüştürmeye ne dersiniz ? Çok hoş değil, ama gerçekten kompakt.

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


Eğer işlenenler zaten boole değilse bu başarısız olur. Çok daha iyi bir fikirB = ((!state1)!==(!state2))
Doin

Doğru, ancak türlerden emin değilseniz yaptığınız gibi onları işlenenleri her zaman reddedebilirsiniz: B =!!(!state1 ^ !state2); Ayrıca, neden bu kadar çok parantez? B = !state1 !== !state2; Ya da olumsuzluğu bile bırakabilirsiniz:B = state1 !== state2;
Lajos Meszaros

Parantez netlik sağlamak içindir ve kod yazarken operatör önceliğine ilişkin belgeleri kontrol etmek zorunda değilim! ;-) Son ifadeniz önceki şikayetimden muzdarip: Operandlar boolean değilse başarısız olur. Ama eğer olduğundan eminseniz, o zaman kesinlikle en basit ve en hızlı "mantıksal xor" ifadesidir.
Doin

Son ifade ile kastediyorsanız state1 !== state2, o zaman herhangi bir döküm yapmanız gerekmez, çünkü !==mantıksal bir operatör, bitsel değil. 12 !== 4doğrudur 'xy' !== trueda doğrudur. !=Bunun yerine kullanmak !==isterseniz, döküm yapmak zorunda kalacaksınız.
Lajos Meszaros

1
Her iki sonucudur !==ve !=her zaman boolean ... Eğer yapıyoruz ayrım kesinlikle sorun olmadığını, orada gerekiyordu emin şeydir. Sorun şu ki, istediğimiz XOR işleci gerçekten ifade (Boolean(state1) !== Boolean(state2)). Booleans için, "xy", 12, 4 ve true hepsi doğru değerler ve dönüştürmek gerekir true. öyle ("xy" XOR true)olmalı false, ama ("xy" !== true)bunun yerine true, işaret ettiğiniz gibi. Bu nedenle !==veya !=(her ikisi de) , yalnızca uygulamadan önce argümanlarını boolelara dönüştürürseniz "mantıksal XOR" ile eşdeğerdir .
Doin

2

Yukarıdaki XOR fonksiyonu olarak bu neden olur BENZER mantıksal XOR tam olarak bir mantıksal XOR değil olarak, bu neden olur araçları sonucu "eşit değerleri için yanlış" ve "farklı değerleri için gerçek bir" göz veri tipi eşleme ile.

Bu XOR fonksiyonu gerçek XOR veya mantıksal operatörü olarak çalışacaktır , geçen değerler için doğru ya da yanlış olarak çalışmanın sonuçları olur vasıtasıyla truthy veya falsy . İhtiyaçlarınıza göre kullanın

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

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

"xnor", "===" ile aynıdır.
daniel1426

@ daniel1426 tam olarak değil. İle aynıdır (!!x) === (!!y). Aradaki fark, oyuncudan boole olanıdır. '' === 0yanlış, xnor('', 0)doğru ise.
tschwab

2

Typescript'te (+ sayısal değere değişir):

value : number = (+false ^ +true)

Yani:

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

@ Normal javascript içindeki Sheolf, !!(false ^ true)booleans ile iyi çalışır. Daktiloda + geçerli kılmak için + gereklidir !!(+false ^ +true).
pfg

1

cond1 xor cond2şuna eşittir cond1 + cond 2 == 1:

İşte kanıt:

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

Mantıksal XOR (^^) olmamasının nedeni && ve || herhangi bir tembel-mantık avantajı sağlamaz. Yani sağ ve soldaki her iki ifadenin durumu da değerlendirilmelidir.


0

İşte 2+ değişkenle çalışan ve bonus olarak sayım sağlayan alternatif bir çözüm.

Aşağıda, standart IF ifadelerinde operatörünüz varmış gibi, herhangi bir doğruluk / falsey değeri için mantıksal XOR benzetimi yapmak için daha genel bir çözüm bulunmaktadır:

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

Bunu sevmemin nedeni, aynı zamanda "Bu değişkenlerden kaçının doğrudur?" Yanıtını vermesidir, bu yüzden genellikle bu sonucu önceden depolarım.

Ve katı boole-TRUE xor check davranışı isteyenler için şunları yapın:

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

Sayımı önemsemiyorsanız veya en iyi performansı önemsiyorsanız: doğru / falsy çözümü için, boole'ye zorlanan değerlerde bitsel xor'u kullanın:

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

0

Hey, JavaScript ve TypeScript üzerinde yapmak ve XOR yapmak için bu çözümü buldum.

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

Bu kısa ve anlaşılması kolay birini deneyin

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

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

Bu, herhangi bir veri türü için çalışır


3
Bu, tüm veri türleri için geçerli değildir. Mantıksal bir tip zorlama operatöründe olduğu gibi "foo" xor "bar" ın yanlış olmasını beklerim, çünkü ikisi de doğrudur. Şu anda sizin işlevinizde durum böyle değil. Genel olarak, yapmak true == somebooleangerekli değildir, bu yüzden gerçekten yaptığınız şey, katı olmayan eşitleri bir işleve sarmaktır.
Gijs

Merhaba GiJs, argümanınıza katılıyorum, "foo" ve "bar" gerçeğe uygun değerlerdir. Ama ben fonksiyonun sadece doğruluk / falsy değeri için değil, xor ile aynı çıktıya (sonuçta eşit olmayan değerler doğru, eşit değerler yanlış sonuçlar) neden olacağını akılda tutarak yazıyorum. Ve bu senaryoda daha fazla kullanım buldum. Ama aşağıda başka bir cevapta gerçek mantıksal xor yazıyorum.
Premchandra Singh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.