Mengapa tidak ada xor logis dalam JavaScript?
Mengapa tidak ada xor logis dalam JavaScript?
Jawaban:
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)
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.
true^true
adalah 0, dan false^true
1.
||
dan &&
dapat digunakan sebagai operator logis pada non-boolean (mis. 5 || 7
mengembalikan nilai "bob" && null
kebenaran , mengembalikan nilai falsey) tetapi ^
tidak bisa. Misalnya, 5 ^ 7
sama dengan 2, yang benar.
(true ^ false) !== true
yang membuatnya menjengkelkan dengan perpustakaan yang membutuhkan boolean yang sebenarnya
a ^= true
untuk beralih boolean dan gagal pada beberapa mesin seperti telepon.
Tidak ada operator boolean logis nyata di Javascript (meskipun !
datang cukup dekat). Operator logis hanya akan mengambil true
atau false
sebagai operan dan hanya akan mengembalikan true
atau 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 undefined
atau .. array kosong? Tapi array kosong masih benar.
Mengambil pendekatan array Anda akan berakhir dengan kondisi seperti if ((a ^^ b).length !== 1) {
. Sangat membingungkan.
Konversikan nilai menjadi bentuk Boolean kemudian ambil bitor XOR. Ini akan membantu dengan nilai-nilai non-boolean juga.
Boolean(a) ^ Boolean(b)
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.
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.
var xor1 = !(a === b);
sama denganvar xor1 = a !== b;
!(2 === 3)
adalah true
, tetapi 2
dan 3
yang truthy sehingga 2 XOR 3
harus false
.
Periksa:
Anda dapat menirunya seperti ini:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
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);
B = ((!state1)!==(!state2))
B =!!(!state1 ^ !state2);
Juga, mengapa begitu banyak kurung? B = !state1 !== !state2;
Atau Anda bahkan dapat menghapus negasi:B = state1 !== state2;
state1 !== state2
, maka Anda tidak perlu melakukan casting di sana, karena !==
operator logis, bukan bitwise. 12 !== 4
benar 'xy' !== true
juga benar. Jika Anda akan menggunakan !=
alih-alih !==
, maka Anda harus melakukan casting.
!==
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.
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);}
(!!x) === (!!y)
. Perbedaannya adalah gips ke boolean. '' === 0
itu salah, sementara xnor('', 0)
itu benar.
Dalam Skrip (+ perubahan ke nilai numerik):
value : number = (+false ^ +true)
Begitu:
value : boolean = (+false ^ +true) == 1
!!(false ^ true)
berfungsi baik dengan boolean. Dalam naskah, + diperlukan untuk membuatnya valid !!(+false ^ +true)
.
cond1 xor cond2
setara 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])}`)
}
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.
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.
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
}
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
true == someboolean
itu tidak perlu, jadi sungguh, apa yang Anda lakukan adalah membungkus ketat yang tidak sama dengan fungsi.
!=
adalah bahwa Anda tidak dapat melakukan hal yang samaa ^= b
, karenaa !== b
hanya operator ketimpangan yang ketat .