Tại sao không có xor logic trong JavaScript?


Câu trả lời:


358

JavaScript truy nguyên tổ tiên của nó trở lại C và C không có toán tử XOR logic. Chủ yếu là vì nó không hữu ích. Bitwise XOR cực kỳ hữu ích, nhưng trong tất cả các năm lập trình, tôi chưa bao giờ cần một XOR logic.

Nếu bạn có hai biến boolean, bạn có thể bắt chước XOR với:

if (a != b)

Với hai biến tùy ý, bạn có thể sử dụng !để ép buộc chúng thành các giá trị boolean và sau đó sử dụng cùng một mẹo:

if (!a != !b)

Điều đó khá mơ hồ và chắc chắn sẽ xứng đáng nhận xét. Thật vậy, bạn thậm chí có thể sử dụng toán tử XOR bitwise vào thời điểm này, mặc dù điều này sẽ quá thông minh đối với sở thích của tôi:

if (!a ^ !b)

Vấn đề duy nhất !=là bạn không thể làm như vậy a ^= b, vì a !== bchỉ là toán tử bất đẳng thức nghiêm ngặt .
mcpiroman

79

Javascript có toán tử XOR bitwise: ^

var nb = 5^9 // = 12

Bạn có thể sử dụng nó với booleans và nó sẽ cho kết quả là 0 hoặc 1 (mà bạn có thể chuyển đổi trở lại thành boolean, ví dụ result = !!(op1 ^ op2)). Nhưng như John nói, nó tương đương với result = (op1 != op2), điều này rõ ràng hơn.


28
Đó là XOR bitwise, không logic XOR
Ismail Badawi

66
Bạn có thể sử dụng nó như một xor logic. true^truelà 0 và false^truelà 1.
Gulrass

14
@Pikrass Bạn có thể sử dụng nó như một toán tử logic trên booleans , nhưng không phải trên các loại khác. ||&&có thể được sử dụng như các toán tử logic trên các giá trị không phải 5 || 7là booleans (ví dụ trả về giá trị trung thực, "bob" && nulltrả về giá trị falsey) nhưng ^không thể. Ví dụ, 5 ^ 7bằng 2, đó là sự thật.
Đánh dấu Amery

10
@Pikrass Nhưng thật đáng buồn, (true ^ false) !== trueđiều này gây khó chịu với các thư viện yêu cầu
booleans

2
@Pikrass Bạn không bao giờ nên sử dụng nó như một toán tử logic trên boolean vì việc triển khai phụ thuộc vào hệ điều hành. Tôi đã sử dụng một số loại a ^= trueđể chuyển đổi booleans và nó đã thất bại trên một số máy như điện thoại.
Masadow

30

Không có toán tử boolean logic thực sự trong Javascript (mặc dù !khá gần). Một toán tử logic sẽ chỉ lấy truehoặc falselàm toán hạng và sẽ chỉ trả về truehoặcfalse .

Trong Javascript &&|| lấy tất cả các loại toán hạng và trả về tất cả các loại kết quả hài hước (bất cứ điều gì bạn đưa vào chúng).

Ngoài ra, một toán tử logic phải luôn luôn tính đến các giá trị của cả hai toán hạng.

Trong Javascript &&||thực hiện một phím tắt lười biếng và không đánh giá toán hạng thứ hai trong một số trường hợp nhất định và do đó bỏ qua các tác dụng phụ của nó. Hành vi này là không thể để tạo lại với một xor logic.


a() && b()đánh giá a()và trả về kết quả nếu nó sai. Nếu không thì nó đánh giáb() và trả về kết quả. Do đó, kết quả trả về là trung thực nếu cả hai kết quả là trung thực và sai.

a() || b()đánh giá a()và trả về kết quả nếu nó là sự thật. Nếu không thì nó đánh giáb() và trả về kết quả. Do đó, kết quả trả về là sai lệch nếu cả hai kết quả đều sai lệch và ngược lại.

Vì vậy, ý tưởng chung là đánh giá toán hạng bên trái trước. Toán hạng bên phải chỉ được đánh giá nếu cần thiết. Và giá trị cuối cùng là kết quả. Kết quả này có thể là bất cứ điều gì. Đối tượng, số, chuỗi .. bất cứ điều gì!

Điều này làm cho nó có thể viết những thứ như

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

hoặc là

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

Nhưng giá trị thật của kết quả này cũng có thể được sử dụng để quyết định xem một toán tử logic "thực" sẽ trả về đúng hay sai.

Điều này làm cho nó có thể viết những thứ như

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

hoặc là

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

Nhưng một toán tử xor "logic" ( ^^) sẽ luôn phải đánh giá cả hai toán hạng. Điều này làm cho nó khác với các toán tử "logic" khác chỉ đánh giá toán hạng thứ hai nếu cần thiết. Tôi nghĩ đây là lý do tại sao không có xor "logic" trong Javascript, để tránh nhầm lẫn.


Vì vậy, những gì sẽ xảy ra nếu cả hai toán hạng là giả? Cả hai có thể được trả lại. Nhưng chỉ có một có thể được trả lại. Cái nào? Cái đầu tiên? Hay cái thứ hai? Trực giác của tôi bảo tôi trả về các toán tử đầu tiên nhưng thường "logic" đánh giá từ trái sang phải và trả về giá trị được đánh giá cuối cùng. Hoặc có thể một mảng chứa cả hai giá trị?

Và nếu một toán hạng là trung thực và toán hạng khác là sai, một xor sẽ trả về giá trị trung thực. Hoặc có thể là một mảng chứa một sự thật, để làm cho nó tương thích với trường hợp trước?

Và cuối cùng, điều gì sẽ xảy ra nếu cả hai toán hạng là sự thật? Bạn sẽ mong đợi một cái gì đó giả. Nhưng không có kết quả giả. Vì vậy, các hoạt động không nên trả lại bất cứ điều gì. Vì vậy, có thể undefinedhoặc .. một mảng trống? Nhưng một mảng trống vẫn là sự thật.

Theo cách tiếp cận mảng, bạn sẽ kết thúc với các điều kiện như if ((a ^^ b).length !== 1) {. Rất bối rối.


XOR / ^^ trong bất kỳ ngôn ngữ nào sẽ luôn phải đánh giá cả hai toán hạng vì nó luôn phụ thuộc vào cả hai. Điều tương tự cũng xảy ra với AND / &&, vì tất cả các toán hạng phải là pass trả về true (true trong JS). Ngoại lệ là OR / || vì nó chỉ phải đánh giá toán hạng cho đến khi tìm thấy giá trị trung thực. Nếu toán hạng đầu tiên trong danh sách OR là trung thực, không ai trong số các toán hạng khác sẽ được đánh giá.
Percy

Tuy nhiên, bạn có một điểm tốt là XOR trong JS sẽ phải phá vỡ quy ước được đặt ra bởi AND và OR. Nó thực sự sẽ phải trả về một giá trị boolean thích hợp chứ không phải là một trong hai toán hạng. Bất cứ điều gì khác có thể gây nhầm lẫn / phức tạp.
Percy

9
@Percy AND / && không đánh giá toán hạng thứ hai nếu toán hạng thứ nhất sai. Nó chỉ đánh giá toán hạng cho đến khi tìm thấy giá trị giả.
Robert

@DDS Cảm ơn đã sửa câu trả lời. Tôi hoang mang không biết tại sao tôi lại không nhận ra điều đó. Có lẽ điều này giải thích sự nhầm lẫn của Percy ở một mức độ nào đó.
Robert

Chỉnh sửa của tôi đã bị từ chối, sau đó @matts chỉnh sửa lại chính xác theo cách tôi đã sửa nó, vì vậy tôi đã bỏ lỡ 2 điểm (bệnh sởi) của mình. 3 người đã từ chối và tôi gặp khó khăn với những gì họ sử dụng làm tiêu chí của họ. Thx trưởng thành.
DDS

16

XOR của hai booleans chỉ đơn giản là liệu chúng có khác nhau hay không, do đó:

Boolean(a) !== Boolean(b)

12

Chuyển đổi giá trị thành dạng Boolean sau đó lấy XOR bitwise. Nó sẽ giúp với các giá trị không boolean là tốt.

Boolean(a) ^ Boolean(b)

10

Chuyển sang boolean và sau đó thực hiện xor như -

!!a ^ !!b

1
Lưu ý rằng !!a ^ !!btương đương với !a ^ !b. Các đối số có thể được thực hiện để dễ đọc hơn.
tschwab

9

có ... loại:

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

hoặc dễ đọc hơn:

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

tại sao? không biết.

bởi vì các nhà phát triển javascript nghĩ rằng nó sẽ không cần thiết vì nó có thể được thể hiện bởi các toán tử logic khác, đã được triển khai.

bạn cũng có thể có gon với nand và đó là nó, bạn có thể gây ấn tượng với mọi hoạt động logic có thể khác từ đó.

Cá nhân tôi nghĩ rằng nó có lý do lịch sử dẫn đến các ngôn ngữ cú pháp dựa trên c, trong đó xor kiến ​​thức của tôi không có mặt hoặc ít nhất là không phổ biến.


Vâng, javascript có ops ternary.
mwilcox

Cả C và Java đều có XOR sử dụng ký tự ^ (caret).
veidelis

7

Vâng, chỉ cần làm như sau. Giả sử rằng bạn đang giao dịch với booleans A và B, thì giá trị A XOR B có thể được tính bằng JavaScript bằng cách sử dụng như sau

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

Dòng trước cũng tương đương với dòng sau

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

Cá nhân, tôi thích xor1 vì tôi phải gõ ít ký tự hơn. Tôi tin rằng xor1 cũng nhanh hơn. Nó chỉ thực hiện hai phép tính. xor2 đang thực hiện ba phép tính.

Giải thích trực quan ... Đọc bảng dưới đây (trong đó 0 là sai và 1 là đúng) và so sánh cột thứ 3 và thứ 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     |
------------------------------------------

Thưởng thức.


6
var xor1 = !(a === b);giống nhưvar xor1 = a !== b;
daniel1426

Câu trả lời này sẽ không hoạt động đối với tất cả các loại dữ liệu (như câu trả lời của Premframra). ví dụ !(2 === 3)true, nhưng 23sự thật 2 XOR 3nên được false.
Mariano Desanze

2
Nếu bạn đã đọc tin nhắn của tôi cẩn thận hơn, bạn sẽ nhận thấy rằng tôi đã viết "Giả sử rằng bạn đang giao dịch với booleans A và B ...".
asiby

5

Thủ tục thanh toán:

Bạn có thể bắt chước nó giống như thế này:

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

3
Xin chào, nếu họ thêm toán tử XOR logic vào JavaScript, nó sẽ làm cho ví dụ mã trông gọn gàng hơn nhiều.
Danyal Aytekin

4

Làm thế nào về việc chuyển đổi kết quả int thành một bool với phủ định kép? Không quá đẹp, nhưng thực sự nhỏ gọn.

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


Điều này sẽ thất bại nếu toán hạng chưa được boolean. Ý tưởng tốt hơn nhiều làB = ((!state1)!==(!state2))
Doin

Đúng, nhưng bạn luôn có thể phủ định các toán hạng để truyền chúng, giống như bạn đã làm nếu bạn không chắc chắn về các loại: B =!!(!state1 ^ !state2); Ngoài ra, tại sao rất nhiều dấu ngoặc đơn? B = !state1 !== !state2; Hoặc thậm chí bạn có thể bỏ đi sự phủ định:B = state1 !== state2;
Lajos Meszaros

Dấu ngoặc đơn là cho rõ ràng, và vì vậy tôi không phải kiểm tra các tài liệu về quyền ưu tiên của nhà điều hành khi viết mã! ;-) Biểu thức cuối cùng của bạn bị khiếu nại trước đây của tôi: Không thành công nếu toán hạng không phải là boolean. Nhưng nếu bạn chắc chắn rằng chúng là như vậy, thì đó chắc chắn là biểu thức "logic xor" đơn giản và nhanh nhất.
Doin

Nếu theo biểu thức cuối cùng của bạn state1 !== state2, thì bạn không cần thực hiện bất kỳ phân vai nào ở đó, vì !==là một toán tử logic, không phải là một bitwise. 12 !== 4đúng 'xy' !== truecũng đúng Nếu bạn sử dụng !=thay vì !==, thì bạn sẽ phải thực hiện đúc.
Lajos Meszaros

1
Kết quả của cả hai !==!=luôn luôn là boolean ... không chắc sự khác biệt mà bạn tạo ra được cho là gì, đó hoàn toàn không phải là vấn đề. Vấn đề là toán tử XOR mà chúng ta muốn thực sự là biểu thức (Boolean(state1) !== Boolean(state2)). Đối với booleans, "xy", 12, 4 và true đều là các giá trị trung thực và nên chuyển đổi thành true. vì vậy ("xy" XOR true)nên false, nhưng ("xy" !== true)thay vào đó true, như bạn chỉ ra. Vì vậy, !==hoặc !=(cả hai) tương đương với "XOR logic" khi và chỉ khi bạn chuyển đổi các đối số của chúng thành booleans trước khi áp dụng.
Doin

2

Trong hàm xor ở trên, nó sẽ dẫn đến kết quả SIMILAR vì xor logic không chính xác là xor logic, có nghĩa là nó sẽ dẫn đến "sai cho các giá trị bằng nhau""đúng cho các giá trị khác nhau" khi xem xét loại dữ liệu phù hợp.

Chức năng xor này sẽ làm việc như xor thực tế hoặc toán tử logic , phương tiện nó sẽ cho kết quả đúng hay sai tùy theo các giá trị truyền là truthy hoặc falsy . Sử dụng theo nhu cầu của bạn

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

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

"xnor" giống như "===".
daniel1426

@ daniel1426 không hoàn toàn. Nó giống như (!!x) === (!!y). Sự khác biệt là một diễn viên để boolean. '' === 0là sai, trong khi đó xnor('', 0)là đúng.
tschwab

2

Trong Bản in (Thay đổi + thành giá trị số):

value : number = (+false ^ +true)

Vì thế:

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

@Sheraff trong javascript bình thường, !!(false ^ true)hoạt động tốt với booleans. Trong bản đánh máy, + là bắt buộc để làm cho nó hợp lệ !!(+false ^ +true).
pfg

1

cond1 xor cond2 tương đương với cond1 + cond 2 == 1 :

Đây là bằng chứng:

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

Lý do không có XOR logic (^^) là vì không giống như && và || nó không cho bất kỳ lợi thế logic-lười biếng. Đó là trạng thái của cả hai biểu thức bên phải và bên trái phải được đánh giá.


0

Đây là một giải pháp thay thế hoạt động với hơn 2 biến và cung cấp được tính là tiền thưởng.

Đây là một giải pháp tổng quát hơn để mô phỏng XOR logic cho bất kỳ giá trị trung thực / falsey nào, giống như khi bạn có toán tử trong các câu lệnh IF tiêu chuẩn:

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

Lý do tôi thích điều này là bởi vì nó cũng trả lời "Có bao nhiêu trong số các biến này là sự thật?", Vì vậy tôi thường lưu trữ trước kết quả đó.

Và đối với những người muốn hành vi kiểm tra boolean-TRUE xor nghiêm ngặt, chỉ cần làm:

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

Nếu bạn không quan tâm đến số đếm hoặc nếu bạn quan tâm đến hiệu suất tối ưu: thì chỉ cần sử dụng xor bitwise trên các giá trị được ép buộc thành boolean, cho giải pháp trung thực / giả mạo:

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

0

Xin chào, tôi đã tìm thấy giải pháp này, để thực hiện và XOR trên JavaScript và 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
}

-2

Hãy thử cái này ngắn gọn và dễ hiểu

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

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

Điều này sẽ làm việc cho bất kỳ loại dữ liệu


3
Điều này không làm việc cho tất cả các loại dữ liệu. Như với một toán tử ép buộc kiểu logic, tôi sẽ mong đợi "foo" xor "bar" là sai, bởi vì cả hai đều là sự thật. Đó không phải là trường hợp với chức năng của bạn. Nói chung, làm true == somebooleanlà không cần thiết, vì vậy, thực sự, những gì bạn đã làm là gói những thứ không bằng nghiêm ngặt vào một hàm.
Gijs

Xin chào GiJs, tôi đồng ý lập luận của bạn, "foo" và "bar" là những giá trị trung thực. Nhưng tôi viết hàm lưu ý rằng nó sẽ cho kết quả đầu ra tương tự như xor (kết quả các giá trị không bằng nhau là đúng, kết quả giá trị bằng nhau sai) không chỉ cho giá trị trung thực / giả. Và tôi tìm thấy việc sử dụng nhiều hơn trong kịch bản như vậy. Nhưng tôi đang viết xor logic thực sự trong một câu trả lời khác dưới đây.
Premframra Singh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.