เหตุใดจึงไม่มีตรรกะ xor ใน JavaScript
เหตุใดจึงไม่มีตรรกะ xor ใน JavaScript
คำตอบ:
JavaScript ติดตามบรรพบุรุษของมันกลับไปที่ C และ C ไม่มีตัวดำเนินการ XOR แบบลอจิคัล ส่วนใหญ่เป็นเพราะมันไม่มีประโยชน์ Bitwise XOR มีประโยชน์อย่างยิ่ง แต่ในทุกปีของการเขียนโปรแกรมฉันไม่เคยต้องการ XOR เชิงตรรกะ
หากคุณมีตัวแปรบูลีนสองตัวคุณสามารถเลียนแบบ XOR ด้วย:
if (a != b)
ด้วยตัวแปรตามอำเภอใจสองตัวที่คุณสามารถใช้!
เพื่อบีบบังคับค่าบูลีนแล้วใช้กลอุบายแบบเดียวกัน:
if (!a != !b)
ซึ่งค่อนข้างคลุมเครือและแน่นอนว่าควรได้รับความคิดเห็น แน่นอนคุณสามารถใช้ตัวดำเนินการ XOR bitwise ณ จุดนี้แม้ว่ามันจะฉลาดเกินไปสำหรับรสนิยมของฉัน:
if (!a ^ !b)
Javascript มีตัวดำเนินการ XOR ระดับบิต: ^
var nb = 5^9 // = 12
คุณสามารถใช้มันกับบูลีนและมันจะให้ผลลัพธ์เป็น 0 หรือ 1 (ซึ่งคุณสามารถแปลงกลับเป็นบูลีนเช่นresult = !!(op1 ^ op2)
) แต่อย่างที่จอห์นบอกว่ามันเทียบเท่าresult = (op1 != op2)
ซึ่งชัดเจนกว่า
true^true
คือ 0 และfalse^true
คือ 1
||
และ&&
สามารถใช้เป็นตัวดำเนินการเชิงตรรกะบน non-booleans (เช่น5 || 7
ส่งคืนค่าความจริง"bob" && null
ส่งกลับค่าเท็จ) แต่^
ไม่สามารถทำได้ ตัวอย่างเช่น5 ^ 7
เท่ากับ 2 ซึ่งเป็นความจริง
(true ^ false) !== true
ที่ทำให้มันน่ารำคาญกับห้องสมุดที่ต้องใช้บูลีนจริง ๆ
a ^= true
สลับเป็น booleans และมันล้มเหลวในเครื่องบางอย่างเช่นโทรศัพท์
ไม่มีตัวดำเนินการบูลีนตรรกะจริงใน Javascript (แม้ว่าจะ!
ใกล้เคียงกันมาก) ผู้ประกอบการตรรกะจะใช้เวลาเพียงtrue
หรือfalse
เป็นตัวถูกดำเนินการและจะกลับมาหรือtrue
false
ใน Javascript &&
และ||
รับตัวถูกดำเนินการทุกชนิดและส่งคืนผลลัพธ์ตลก ๆ ทุกชนิด (สิ่งที่คุณป้อนเข้าไป)
นอกจากนี้ผู้ดำเนินการเชิงตรรกะควรคำนึงถึงค่าของตัวถูกดำเนินการทั้งสองด้วย
ใน Javascript &&
และ||
ใช้ช็อตคัตขี้เกียจและไม่ประเมินตัวถูกดำเนินการที่สองในบางกรณีและละเลยผลข้างเคียง พฤติกรรมนี้เป็นไปไม่ได้ที่จะสร้างขึ้นใหม่ด้วยตรรกะ 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
แต่ค่าความจริงของผลลัพธ์นี้ยังสามารถใช้ในการตัดสินใจว่าตัวดำเนินการเชิงตรรกะ "ของจริง" จะกลับมาจริงหรือเท็จ
สิ่งนี้ทำให้สามารถเขียนสิ่งต่าง ๆ เช่น
if (typeof image.hasAttribute === 'function' && image.hasAttribute('src')) {
หรือ
if (image.hasAttribute('alt') || image.hasAttribute('title')) {
แต่ตัวดำเนินการ "ตรรกะ" xor ( ^^
) จะต้องประเมินตัวถูกดำเนินการทั้งสองเสมอ สิ่งนี้ทำให้แตกต่างจากตัวดำเนินการ "ตรรกะ" อื่น ๆ ซึ่งประเมินตัวถูกดำเนินการตัวที่สองเฉพาะในกรณีที่จำเป็นเท่านั้น ฉันคิดว่านี่เป็นสาเหตุที่ไม่มี "ตรรกะ" xor ใน Javascript เพื่อหลีกเลี่ยงความสับสน
แล้วจะเกิดอะไรขึ้นถ้าตัวถูกดำเนินการทั้งสองผิดพลาด? ทั้งสองสามารถส่งคืนได้ แต่สามารถคืนได้เพียงรายการเดียวเท่านั้น อันไหน? คนแรก? หรืออันที่สอง? ปรีชาญาณของฉันบอกให้ฉันกลับผู้ดำเนินการรายแรก แต่มักจะประเมินตรรกะจากซ้ายไปขวาและคืนค่าที่ประเมินล่าสุด หรืออาจเป็นอาร์เรย์ที่มีค่าทั้งสอง?
และถ้าตัวถูกดำเนินการตัวใดตัวหนึ่งเป็นความจริงและตัวถูกดำเนินการตัวหนึ่งนั้นเป็นคนโกหก xor ควรกลับคืนความจริง หรืออาจเป็นอาเรย์ที่บรรจุสัจธรรมเพื่อให้เข้ากันได้กับเคสก่อนหน้า?
และในที่สุดสิ่งที่จะเกิดขึ้นถ้าตัวถูกดำเนินการทั้งสองเป็นจริง คุณคาดหวังบางสิ่งบางอย่างผิดพลาด แต่ไม่มีผลลัพธ์ที่เป็นเท็จ ดังนั้นการดำเนินการไม่ควรส่งคืนสิ่งใด ดังนั้นอาจundefined
หรือ .. อาร์เรย์ว่างเปล่า? แต่อาเรย์ที่ว่างยังคงเป็นความจริง
if ((a ^^ b).length !== 1) {
การใช้วิธีอาร์เรย์ที่คุณจะจบลงด้วยสภาพเช่น สับสนมาก
XOR ของสองบูลีนเป็นเพียงว่าพวกเขาแตกต่างกันดังนั้น:
Boolean(a) !== Boolean(b)
แปลงค่าเป็นรูปแบบบูลีนจากนั้นใช้ค่า XOR มันจะช่วยให้มีค่าที่ไม่ใช่แบบบูลเช่นกัน
Boolean(a) ^ Boolean(b)
แปลงเป็นบูลีนแล้วทำ xor like -
!!a ^ !!b
!!a ^ !!b
!a ^ !b
อาร์กิวเมนต์สามารถอ่านได้ง่ายกว่า
มี ... ประเภทของ:
if( foo ? !bar : bar ) {
...
}
หรือง่ายต่อการอ่าน:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
ทำไม? dunno
เพราะผู้พัฒนาจาวาสคริปต์คิดว่ามันจะไม่จำเป็นเพราะมันสามารถแสดงออกได้โดยผู้ประกอบการอื่น ๆ ที่ดำเนินการแล้วตรรกะ
คุณอาจจะมีแค่ gon กับ nand และคุณสามารถสร้างความประทับใจให้กับการดำเนินการทางตรรกะอื่น ๆ
โดยส่วนตัวฉันคิดว่ามันมีเหตุผลทางประวัติศาสตร์ที่ขับเคลื่อนจากภาษาไวยากรณ์แบบอิง c ซึ่งความรู้ของฉันไม่มีอยู่หรืออย่างน้อยก็ผิดปกติ
ใช่เพียงทำต่อไปนี้ สมมติว่าคุณกำลังจัดการกับ booleans A และ B ดังนั้นค่า A XOR B สามารถคำนวณใน JavaScript โดยใช้สิ่งต่อไปนี้
var xor1 = !(a === b);
บรรทัดก่อนหน้านี้ยังเทียบเท่ากับสิ่งต่อไปนี้
var xor2 = (!a !== !b);
โดยส่วนตัวฉันชอบ xor1 ตั้งแต่ฉันต้องพิมพ์ตัวอักษรน้อยลง ฉันเชื่อว่า xor1 ก็เร็วขึ้นเช่นกัน มันแค่ทำการคำนวณสองครั้ง xor2 กำลังทำการคำนวณสามครั้ง
คำอธิบายภาพ ... อ่านตารางร้อง (โดยที่ 0 หมายถึงเท็จและ 1 หมายถึงจริง) และเปรียบเทียบคอลัมน์ที่ 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 |
------------------------------------------
สนุก.
var xor1 = !(a === b);
เป็นเช่นเดียวกับvar xor1 = a !== b;
!(2 === 3)
เป็นtrue
แต่2
และ3
มีtruthyดังนั้นควรจะเป็น2 XOR 3
false
เช็คเอาท์:
คุณสามารถเลียนแบบได้ดังนี้:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
วิธีการเกี่ยวกับการแปลงผลลัพธ์intเพื่อboolกับการปฏิเสธคู่? ไม่สวย แต่กะทัดรัดจริงๆ
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);
นอกจากนี้ทำไมวงเล็บจำนวนมาก? B = !state1 !== !state2;
หรือคุณอาจปล่อยให้การปฏิเสธ:B = state1 !== state2;
state1 !== state2
ไม่จำเป็นต้องทำการคัดเลือกนักแสดงที่นั่นเพราะ!==
เป็นผู้ดำเนินการเชิงตรรกะไม่ใช่บิต 12 !== 4
เป็นความจริง'xy' !== true
ก็เป็นจริงเช่นกัน หากคุณต้องการใช้!=
แทนคุณ!==
จะต้องทำการคัดเลือกนักแสดง
!==
และ!=
เป็นบูลีนเสมอ ... ไม่แน่ใจว่าความแตกต่างที่คุณทำนั้นควรจะเป็นอะไรนั่นไม่ใช่ปัญหาอย่างแน่นอน ปัญหาคือผู้ดำเนินการ XOR ที่เราต้องการนั้นเป็นนิพจน์(Boolean(state1) !== Boolean(state2))
อย่างแท้จริง สำหรับ booleans "เซ็กซี่", 12, 4 และtrue
เป็นค่า truthy true
ทั้งหมดและควรแปลง ดังนั้น("xy" XOR true)
ควรจะเป็นfalse
แต่("xy" !== true)
เป็นแทนtrue
ตามที่คุณชี้ให้เห็น ดังนั้น!==
หรือเท่ากับ!=
(ทั้งสอง) เทียบเท่ากับ "XOR แบบลอจิคัล" หากว่าคุณแปลงอาร์กิวเมนต์เป็น booleans ก่อนที่จะใช้
ในฟังก์ชั่น xor ด้านบนมันจะส่งผลให้ผลลัพธ์SIMILARเป็นตรรกะ xor ไม่ได้ว่าตรรกะ xor อย่างแน่นอนหมายความว่ามันจะส่งผล"เท็จสำหรับค่าเท่ากัน"และ"เป็นจริงสำหรับค่าที่แตกต่าง"กับการจับคู่ชนิดข้อมูลในการพิจารณา
ฟังก์ชั่น xor นี้จะทำงานเป็น xor จริงหรือผู้ประกอบการตรรกะหมายถึงว่ามันจะส่งผลตามจริงหรือเท็จกับค่าผ่านมีtruthyหรือfalsy ใช้ตามความต้องการของคุณ
function xor(x,y){return true==(!!x!==!!y);}
function xnor(x,y){return !xor(x,y);}
(!!x) === (!!y)
มันเป็นเช่นเดียวกับ ความแตกต่างคือการโยนเพื่อบูลีน '' === 0
เป็นเท็จในขณะที่xnor('', 0)
เป็นจริง
ใน typescript (+ เปลี่ยนเป็นค่าตัวเลข):
value : number = (+false ^ +true)
ดังนั้น:
value : boolean = (+false ^ +true) == 1
!!(false ^ true)
งานได้ดีกับ booleans ใน typescript + !!(+false ^ +true)
เป็นสิ่งจำเป็นที่จะทำให้มันถูกต้อง
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])}`)
}
เหตุผลที่ไม่มีเหตุผล XOR (^^) เป็นเพราะต่างจาก && และ || มันไม่ให้ความได้เปรียบใด ๆ กับสันหลังยาว นั่นคือสถานะของนิพจน์ทั้งสองทางด้านขวาและซ้ายจะต้องได้รับการประเมิน
ต่อไปนี้เป็นโซลูชันทางเลือกที่ทำงานกับตัวแปร 2+ ตัวและให้นับเป็นโบนัส
ต่อไปนี้เป็นโซลูชันทั่วไปเพิ่มเติมเพื่อจำลองโลจิคัล XOR สำหรับค่าความจริง / เท็จเช่นเดียวกับที่คุณมีโอเปอเรเตอร์ในคำสั่ง IF มาตรฐาน:
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.
หากคุณไม่สนใจเกี่ยวกับการนับหรือถ้าคุณสนใจประสิทธิภาพที่ดีที่สุด: ให้ใช้ bitor xor กับค่าที่บังคับให้บูลีนสำหรับวิธีแก้ปัญหาความจริง / เท็จ
if( !!v1 ^ !!v2 ^ !!v3 ^ !!v4 ^ !!v5 )
// etc.
สวัสดีฉันพบโซลูชันนี้เพื่อสร้างและ XOR บน JavaScript และ 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
}
ลองอันนี้สั้นและเข้าใจง่าย
function xor(x,y){return true==(x!==y);}
function xnor(x,y){return !xor(x,y);}
สิ่งนี้จะใช้ได้กับข้อมูลทุกประเภท
true == someboolean
ไม่จำเป็นดังนั้นจริงๆสิ่งที่คุณทำคือการห่อที่เข้มงวดไม่เท่ากับในฟังก์ชั่น
!=
คือคุณไม่สามารถทำเช่นเดียวกับa ^= b
เพราะa !== b
เป็นเพียงผู้ดำเนินการความไม่เท่าเทียมที่เข้มงวด