Почему в JavaScript нет логического xor? - PullRequest
172 голосов
/ 27 декабря 2010

Почему в JavaScript нет логического xor?

Ответы [ 15 ]

330 голосов
/ 27 декабря 2010

JavaScript ведет свое происхождение от C, а в C нет логического оператора XOR. Главным образом потому, что это не полезно. Побитовое XOR чрезвычайно полезно, но за все мои годы программирования мне никогда не требовался логический XOR.

Если у вас есть две логические переменные, вы можете имитировать XOR с помощью:

if (a != b)

С двумя произвольными переменными вы можете использовать !, чтобы привести их к логическим значениям, а затем использовать тот же трюк:

if (!a != !b)

Хотя это довольно неясно и заслуживает комментария. В самом деле, вы могли бы даже использовать побитовый оператор XOR на этом этапе, хотя это было бы слишком умным на мой вкус:

if (!a ^ !b)
73 голосов
/ 27 декабря 2010

В JavaScript есть побитовый оператор XOR: ^

var nb = 5^9 // = 12

Вы можете использовать его с логическими значениями, и он даст результат в виде 0 или 1 (который можно преобразовать обратно в логическое значение, например, result = !!(op1 ^ op2)). Но, как сказал Джон, это эквивалентно result = (op1 != op2), что более понятно.

28 голосов
/ 14 марта 2012

В 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

Но истинное значение этого результата можеттакже используется для определения того, должен ли «реальный» логический оператор возвратить true или false.

Это позволяет писать такие вещи, как

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

или

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

Но «логический» оператор xor (^^) всегда должен оценивать оба операнда.Это отличает его от других «логических» операторов, которые оценивают второй операнд только при необходимости.Я думаю, именно поэтому в Javascript нет «логического» xor, чтобы избежать путаницы.


Так что же произойдет, если оба операнда ложные?Оба могут быть возвращены.Но только один может быть возвращен.Который из?Первый?Или второй?Моя интуиция подсказывает мне вернуть первые, но обычно «логические» операторы, вычисленные слева направо, и вернуть последнее оцененное значение.Или, может быть, массив, содержащий оба значения?

И если один операнд является истинным, а другой операндом ложным, xor должен возвращать истинный.Или, может быть, массив, содержащий истинный, чтобы сделать его совместимым с предыдущим случаем?

И, наконец, что должно произойти, если оба операнда верны?Вы ожидаете чего-то ложного.Но нет никаких ложных результатов.Так что операция не должна ничего возвращать.Так может undefined или .. пустой массив?Но пустой массив все еще правдив.

При использовании подхода с массивами вы получите условия, подобные if ((a ^^ b).length !== 1) {.Очень запутанно.

11 голосов
/ 25 июня 2015

XOR двух логических выражений просто, отличаются ли они, поэтому:

Boolean(a) !== Boolean(b)
9 голосов
/ 27 декабря 2010

есть ... вроде:

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

или проще для чтения:

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

почему? Не знаю.

потому что разработчики javascript думали, что это будет не нужно, поскольку это может быть выражено другими, уже реализованными, логическими операторами.

вы также можете просто получить nand, вот и все, вы можете произвести впечатление на любую другую логическую операцию из этого.

Лично я думаю, что у него есть исторические причины, которые берут начало от языков синтаксиса на основе c, где, насколько мне известно, xor отсутствует или, по крайней мере, крайне необычен.

7 голосов
/ 05 августа 2013

Да, просто сделайте следующее.Предполагая, что вы имеете дело с логическими значениями A и B, тогда значение 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     |
------------------------------------------

Наслаждайтесь.

4 голосов
/ 26 апреля 2019

Преобразуйте значения в логическую форму, затем возьмите битовое XOR.Это поможет и с не булевыми значениями.

Boolean(a) ^ Boolean(b)
4 голосов
/ 26 апреля 2019

Обратить до логического значения, а затем выполнить xor как -

!!a ^ !!b
4 голосов
/ 27 декабря 2012

Как насчет преобразования результата 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);
4 голосов
/ 27 декабря 2010

Выезд:

Вы можете имитировать что-то вроде этого:

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