Neden JavaScript'te mantıksal xor yok?
Neden JavaScript'te mantıksal xor yok?
Yanıtlar:
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)
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.
true^true
0 ve false^true
1'dir.
||
ve boolean &&
olmayanlar üzerinde mantıksal işleçler olarak kullanılabilir (örn. 5 || 7
doğru bir değer döndürür, bir falsey değeri "bob" && null
döndürür), ancak ^
kullanılamaz. Örneğin 5 ^ 7
, doğru olan 2'ye eşittir.
(true ^ false) !== true
bu gerçek booleans gerektiren kütüphaneler ile sinir bozucu
a ^= true
booleans geçiş yapmak için bir tür kullanıyordum ve telefon gibi bazı makinelerde başarısız.
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 true
veya false
işlenen olarak alınır ve yalnızca true
veya 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ı.
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)
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, 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.
var xor1 = !(a === b);
ile aynıvar xor1 = a !== b;
!(2 === 3)
olduğunu true
, ancak 2
ve 3
vardır truthy böylece 2 XOR 3
olmalıdır false
.
Çıkış yapmak:
Bunun gibi bir şeyi taklit edebilirsiniz:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
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);
B = ((!state1)!==(!state2))
B =!!(!state1 ^ !state2);
Ayrıca, neden bu kadar çok parantez? B = !state1 !== !state2;
Ya da olumsuzluğu bile bırakabilirsiniz:B = state1 !== state2;
state1 !== state2
, o zaman herhangi bir döküm yapmanız gerekmez, çünkü !==
mantıksal bir operatör, bitsel değil. 12 !== 4
doğrudur 'xy' !== true
da doğrudur. !=
Bunun yerine kullanmak !==
isterseniz, döküm yapmak zorunda kalacaksınız.
!==
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 .
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);}
(!!x) === (!!y)
. Aradaki fark, oyuncudan boole olanıdır. '' === 0
yanlış, xnor('', 0)
doğru ise.
Typescript'te (+ sayısal değere değişir):
value : number = (+false ^ +true)
Yani:
value : boolean = (+false ^ +true) == 1
!!(false ^ true)
booleans ile iyi çalışır. Daktiloda + geçerli kılmak için + gereklidir !!(+false ^ +true)
.
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])}`)
}
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.
İş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.
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
}
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
true == someboolean
gerekli değildir, bu yüzden gerçekten yaptığınız şey, katı olmayan eşitleri bir işleve sarmaktır.
!=
aynı şeyi yapamayacağınızdıra ^= b
, çünküa !== b
sadece katı eşitsizlik operatörüdür.