Mengapa tidak ada xor logis dalam JavaScript?

Jawaban:

358

JavaScript melacak leluhurnya kembali ke C, dan C tidak memiliki operator XOR yang logis. Terutama karena itu tidak berguna. Bitwise XOR sangat berguna, tetapi dalam semua tahun pemrograman saya, saya tidak pernah membutuhkan XOR logis.

Jika Anda memiliki dua variabel boolean, Anda dapat meniru XOR dengan:

if (a != b)

Dengan dua variabel arbitrer yang dapat Anda gunakan !untuk memaksa mereka ke nilai boolean dan kemudian menggunakan trik yang sama:

if (!a != !b)

Itu cukup tidak jelas dan tentu saja layak mendapatkan komentar. Memang, Anda bahkan bisa menggunakan operator XOR bitwise pada titik ini, meskipun ini akan terlalu pintar untuk seleraku:

if (!a ^ !b)
John Kugelman
sumber
Satu-satunya masalah !=adalah bahwa Anda tidak dapat melakukan hal yang sama a ^= b, karena a !== bhanya operator ketimpangan yang ketat .
mcpiroman
79

Javascript memiliki operator XOR bitwise: ^

var nb = 5^9 // = 12

Anda dapat menggunakannya dengan booleans dan itu akan memberikan hasilnya sebagai 0 atau 1 (yang dapat Anda konversi kembali ke boolean, misalnya result = !!(op1 ^ op2)). Tapi seperti kata John, itu setara dengan result = (op1 != op2), yang lebih jelas.

Pikrass
sumber
28
Itu XOR bitwise, bukan XOR logis
Ismail Badawi
66
Anda dapat menggunakannya sebagai xor logis. true^trueadalah 0, dan false^true1.
Pikrass
14
@Pikrass Anda dapat menggunakannya sebagai operator logis pada boolean , tetapi tidak pada tipe lainnya. ||dan &&dapat digunakan sebagai operator logis pada non-boolean (mis. 5 || 7mengembalikan nilai "bob" && nullkebenaran , mengembalikan nilai falsey) tetapi ^tidak bisa. Misalnya, 5 ^ 7sama dengan 2, yang benar.
Mark Amery
10
@Pikrass Tapi sayangnya,, (true ^ false) !== trueyang membuatnya menjengkelkan dengan perpustakaan yang membutuhkan boolean yang sebenarnya
Izkata
2
@Pikrass Anda tidak boleh menggunakannya sebagai operator logis pada boolean karena implementasi bergantung pada OS. Saya menggunakan beberapa jenis a ^= trueuntuk beralih boolean dan gagal pada beberapa mesin seperti telepon.
Masadow
30

Tidak ada operator boolean logis nyata di Javascript (meskipun !datang cukup dekat). Operator logis hanya akan mengambil trueatau falsesebagai operan dan hanya akan mengembalikan trueatau false.

Dalam Javascript &&dan ||ambil semua jenis operan dan kembalikan semua jenis hasil lucu (apa pun yang Anda masukkan ke dalamnya).

Juga operator logis harus selalu memperhitungkan nilai kedua operan.

Dalam Javascript &&dan ||mengambil jalan pintas malas dan tidak mengevaluasi operan kedua dalam kasus-kasus tertentu dan dengan demikian mengabaikan efek samping. Perilaku ini tidak mungkin dibuat ulang dengan xor logis.


a() && b()mengevaluasi a()dan mengembalikan hasilnya jika itu palsu. Kalau tidak, ia mengevaluasi b()dan mengembalikan hasilnya. Oleh karena itu hasil yang dikembalikan adalah benar jika kedua hasil benar, dan sebaliknya sebaliknya.

a() || b()mengevaluasi a()dan mengembalikan hasilnya jika itu benar. Kalau tidak, ia mengevaluasi b()dan mengembalikan hasilnya. Oleh karena itu hasil yang dikembalikan adalah falsy jika kedua hasil falsy, dan sebaliknya sebaliknya.

Jadi ide umumnya adalah mengevaluasi operan kiri terlebih dahulu. Operan yang tepat hanya akan dievaluasi jika perlu. Dan nilai terakhir adalah hasilnya. Hasil ini bisa apa saja. Benda, angka, string .. terserah!

Ini memungkinkan untuk menulis hal-hal seperti

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

atau

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

Tetapi nilai kebenaran dari hasil ini juga dapat digunakan untuk memutuskan apakah operator logis "nyata" akan mengembalikan benar atau salah.

Ini memungkinkan untuk menulis hal-hal seperti

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

atau

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

Tetapi operator x "logis" ( ^^) harus selalu mengevaluasi kedua operan. Ini membuatnya berbeda dengan operator "logis" lainnya yang mengevaluasi operan kedua hanya jika perlu. Saya pikir ini sebabnya tidak ada "logis" xor dalam Javascript, untuk menghindari kebingungan.


Jadi apa yang harus terjadi jika kedua operan itu palsu? Keduanya bisa dikembalikan. Tetapi hanya satu yang bisa dikembalikan. Yang mana? Yang pertama? Atau yang kedua? Intuisi saya memberi tahu saya untuk mengembalikan operator pertama tetapi biasanya "logis" mengevaluasi dari kiri ke kanan dan mengembalikan nilai yang terakhir dievaluasi. Atau mungkin array yang mengandung kedua nilai?

Dan jika satu operan adalah kebenaran dan operan lainnya adalah palsu, sebuah xor harus mengembalikan yang benar. Atau mungkin array yang berisi yang benar, agar kompatibel dengan case sebelumnya?

Dan akhirnya, apa yang harus terjadi jika kedua operan itu benar? Anda akan mengharapkan sesuatu yang palsu. Tetapi tidak ada hasil palsu. Jadi operasi seharusnya tidak mengembalikan apa pun. Jadi mungkin undefinedatau .. array kosong? Tapi array kosong masih benar.

Mengambil pendekatan array Anda akan berakhir dengan kondisi seperti if ((a ^^ b).length !== 1) {. Sangat membingungkan.

Robert
sumber
XOR / ^^ dalam bahasa apa pun harus selalu mengevaluasi kedua operan karena selalu bergantung pada keduanya. Hal yang sama berlaku untuk AND / &&, karena semua operan harus benar (benar di JS) pengembalian pass. Pengecualiannya adalah OR / || karena itu hanya harus mengevaluasi operan sampai menemukan nilai yang benar. Jika operan pertama dalam daftar ATAU benar, tidak ada yang lain akan dievaluasi.
Percy
Anda membuat poin yang baik, bahwa XOR di JS harus melanggar konvensi yang ditetapkan oleh AND dan OR. Ini sebenarnya harus mengembalikan nilai boolean yang tepat daripada salah satu dari dua operan. Hal lain dapat menyebabkan kebingungan / kerumitan.
Percy
9
@Percy AND / && tidak mengevaluasi operan kedua jika yang pertama salah. Itu hanya mengevaluasi operan sampai menemukan nilai palsu.
Robert
@DDS Terima kasih telah memperbaiki jawabannya. Saya bingung mengapa saya tidak memperhatikannya sendiri. Mungkin ini menjelaskan kebingungan Percy sampai batas tertentu.
Robert
Hasil edit saya ditolak, setelah itu @matts diedit ulang persis seperti cara saya memperbaikinya, jadi saya melewatkan 2 poin saya. 3 orang menolaknya dan saya bingung apa yang mereka gunakan sebagai kriteria mereka. Terima kasih.
DDS
16

XOR dari dua boolean hanyalah apakah mereka berbeda, oleh karena itu:

Boolean(a) !== Boolean(b)
DomQ
sumber
12

Konversikan nilai menjadi bentuk Boolean kemudian ambil bitor XOR. Ini akan membantu dengan nilai-nilai non-boolean juga.

Boolean(a) ^ Boolean(b)
Aman Kaushal
sumber
10

Terselubung ke boolean dan kemudian melakukan xor seperti -

!!a ^ !!b
toyeca
sumber
1
Catatan yang !!a ^ !!bsetara dengan !a ^ !b. Argumen bisa dibuat yang lebih mudah dibaca.
tschwab
9

ada ... semacam:

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

atau lebih mudah dibaca:

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

Mengapa? tidak tahu

karena pengembang javascript berpikir itu tidak perlu karena dapat diekspresikan oleh operator lain yang sudah diimplementasikan.

Anda bisa saja memiliki gon dengan nand dan hanya itu, Anda dapat mengesankan setiap operasi logis yang mungkin dari itu.

Saya pribadi berpikir itu memiliki alasan historis yang mendorong dari bahasa sintaksis berbasis-c, di mana setahu saya xor tidak ada atau paling tidak jarang.

The Surrican
sumber
Ya, javascript memiliki operasi terner.
mwilcox
Baik C dan Java memiliki XOR menggunakan karakter ^ (caret).
veidelis
7

Ya, lakukan saja yang berikut ini. Dengan asumsi bahwa Anda berurusan dengan boolean A dan B, maka nilai XOR B dapat dihitung dalam JavaScript menggunakan berikut ini

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

Baris sebelumnya juga setara dengan yang berikut ini

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

Secara pribadi, saya lebih suka xor1 karena saya harus mengetikkan lebih sedikit karakter. Saya percaya bahwa xor1 juga lebih cepat. Itu hanya melakukan dua perhitungan. xor2 sedang melakukan tiga perhitungan.

Penjelasan Visual ... Baca tabel di bawah ini (di mana 0 berarti false dan 1 berarti benar) dan bandingkan kolom 3 dan 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     |
------------------------------------------

Nikmati.

asiby
sumber
6
var xor1 = !(a === b);sama denganvar xor1 = a !== b;
daniel1426
Jawaban ini tidak akan bekerja untuk semua tipe data (seperti jawaban Premchandra). misalnya !(2 === 3)adalah true, tetapi 2dan 3yang truthy sehingga 2 XOR 3harus false.
Mariano Desanze
2
Jika Anda membaca pesan saya lebih hati-hati, Anda akan memperhatikan bahwa saya menulis "Dengan asumsi bahwa Anda berurusan dengan boolean A dan B ...".
asiby
5

Periksa:

Anda dapat menirunya seperti ini:

if( ( foo && !bar ) || ( !foo && bar ) ) {
  ...
}
Sarfraz
sumber
3
Hei jika mereka menambahkan operator logis XOR ke JavaScript itu akan membuat contoh kode terlihat jauh lebih bersih.
Danyal Aytekin
4

Bagaimana mengubah hasil int ke bool dengan negasi ganda? Tidak begitu cantik, tetapi sangat kompak.

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

Lajos Meszaros
sumber
Ini akan gagal jika operan belum boolean. Ide yang jauh lebih baik adalahB = ((!state1)!==(!state2))
Doin
Benar, tetapi Anda selalu dapat meniadakan operan untuk melemparkannya, seperti yang Anda lakukan jika Anda tidak yakin dengan jenisnya: B =!!(!state1 ^ !state2); Juga, mengapa begitu banyak kurung? B = !state1 !== !state2; Atau Anda bahkan dapat menghapus negasi:B = state1 !== state2;
Lajos Meszaros
Parenthesis adalah untuk kejelasan, dan juga jadi saya tidak perlu memeriksa dokumen tentang prioritas operator saat menulis kode! ;-) Ekspresi terakhir Anda menderita keluhan saya sebelumnya: Gagal jika operan tidak boolean. Tetapi jika Anda yakin mereka, maka itu pasti ekspresi "logis logis" yang paling sederhana dan tercepat.
Lakukan
Jika dengan ungkapan terakhir yang Anda maksud state1 !== state2, maka Anda tidak perlu melakukan casting di sana, karena !==operator logis, bukan bitwise. 12 !== 4benar 'xy' !== truejuga benar. Jika Anda akan menggunakan !=alih-alih !==, maka Anda harus melakukan casting.
Lajos Meszaros
1
Hasil dari keduanya !==dan !=selalu boolean ... tidak yakin apa perbedaan yang Anda buat seharusnya ada, itu sama sekali bukan masalahnya. Masalahnya adalah bahwa operator XOR yang kita inginkan benar-benar ekspresi (Boolean(state1) !== Boolean(state2)). Untuk boolean, "xy", 12, 4 dan true semuanya adalah nilai yang benar, dan harus dikonversi menjadi true. jadi ("xy" XOR true)seharusnya false, tetapi ("xy" !== true)sebaliknya true, seperti yang Anda tunjukkan. Jadi !==atau !=sama dengan "logis XOR" jika dan hanya jika Anda mengonversi argumen mereka menjadi boolean sebelum mendaftar.
Lakukan
2

Dalam fungsi xor di atas akan menghasilkan hasil SIMILAR karena xor logis tidak persis xor logis, artinya akan menghasilkan "false untuk nilai yang sama" dan "true untuk nilai yang berbeda" dengan pencocokan jenis data sebagai pertimbangan.

Fungsi XOR ini akan bekerja sebagai xor aktual atau operator logis , berarti itu akan menghasilkan sesuai benar atau salah dengan nilai-nilai yang lewat adalah truthy atau falsy . Gunakan sesuai dengan kebutuhan Anda

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

function xnor(x,y){return !xor(x,y);}
Premchandra Singh
sumber
"xnor" sama dengan "===".
daniel1426
@ daniel1426 tidak cukup. Itu sama dengan (!!x) === (!!y). Perbedaannya adalah gips ke boolean. '' === 0itu salah, sementara xnor('', 0)itu benar.
tschwab
2

Dalam Skrip (+ perubahan ke nilai numerik):

value : number = (+false ^ +true)

Begitu:

value : boolean = (+false ^ +true) == 1
Witold Kaczurba
sumber
@ Sheraff dalam javascript normal, !!(false ^ true)berfungsi baik dengan boolean. Dalam naskah, + diperlukan untuk membuatnya valid !!(+false ^ +true).
pfg
1

cond1 xor cond2setara dengan cond1 + cond 2 == 1:

Inilah buktinya:

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

madjaoue
sumber
0

Alasan tidak ada XOR logis (^^) adalah karena tidak seperti && dan || itu tidak memberikan keuntungan malas-logika. Itu adalah keadaan kedua ekspresi di kanan dan kiri harus dievaluasi.

pengguna7163886
sumber
0

Berikut ini solusi alternatif yang berfungsi dengan 2+ variabel dan memberikan hitungan sebagai bonus.

Berikut adalah solusi yang lebih umum untuk mensimulasikan XOR logis untuk nilai kebenaran / falsey, sama seperti jika Anda memiliki operator dalam pernyataan IF standar:

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

Alasan saya suka ini, adalah karena ia juga menjawab "Berapa banyak dari variabel-variabel ini yang benar?", Jadi saya biasanya menyimpannya terlebih dahulu.

Dan bagi mereka yang menginginkan perilaku cek ketat boolean-TRUE, hanya:

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

Jika Anda tidak peduli dengan penghitungan, atau jika Anda peduli tentang kinerja optimal: maka gunakan bitor xor pada nilai yang dipaksakan ke boolean, untuk solusi yang benar / salah:

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

Hai saya menemukan solusi ini, untuk membuat dan XOR pada JavaScript dan 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
}
Lucas Solares
sumber
-2

Coba ini pendek dan mudah dimengerti

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

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

Ini akan bekerja untuk semua tipe data

Premchandra Singh
sumber
3
Ini tidak berfungsi untuk semua tipe data. Seperti halnya operator paksaan jenis logis, saya berharap "foo" xor "bar" menjadi salah, karena keduanya benar. Saat ini tidak demikian halnya dengan fungsi Anda. Secara umum, melakukan true == somebooleanitu tidak perlu, jadi sungguh, apa yang Anda lakukan adalah membungkus ketat yang tidak sama dengan fungsi.
Gijs
Halo, saya setuju dengan argumen Anda, "foo" dan "bar" adalah nilai yang sebenarnya. Tapi saya menulis fungsi dengan mengingat bahwa itu akan menghasilkan output yang sama seperti xor (nilai un-equal menghasilkan true, nilai equal menghasilkan false) bukan untuk nilai true / falsy saja. Dan saya menemukan lebih banyak penggunaan dalam skenario seperti itu. Tetapi saya menulis xor logis sejati dalam jawaban lain di bawah ini.
Premchandra Singh