Почему в JavaScript нет логического xor?
Почему в JavaScript нет логического xor?
Ответы:
JavaScript ведет свое происхождение от C, а C не имеет логического оператора XOR. Главным образом потому, что это не полезно. Побитовое XOR чрезвычайно полезно, но за все мои годы программирования мне никогда не требовался логический XOR.
Если у вас есть две логические переменные, вы можете имитировать XOR с помощью:
if (a != b)
С двумя произвольными переменными вы можете использовать !
их для приведения к логическим значениям, а затем использовать тот же трюк:
if (!a != !b)
Это довольно неясно, хотя и, безусловно, заслуживает комментария. В самом деле, вы могли бы даже использовать побитовый оператор XOR на этом этапе, хотя это было бы слишком умным на мой вкус:
if (!a ^ !b)
В JavaScript есть побитовый оператор XOR: ^
var nb = 5^9 // = 12
Вы можете использовать его с логическими значениями, и он даст результат в виде 0 или 1 (например, вы можете конвертировать обратно в логическое значение result = !!(op1 ^ op2)
). Но, как сказал Джон, это эквивалентно result = (op1 != op2)
, что более понятно.
true^true
0 и false^true
1
||
и &&
может использоваться в качестве логических операторов для небулевых (например, 5 || 7
возвращает истинное значение, "bob" && null
возвращает ложное значение), но ^
не может. Например, 5 ^ 7
равно 2, что является правдой.
(true ^ false) !== true
это делает его раздражающим в библиотеках, которые требуют фактических логических значений
a ^= true
переключение логических значений, и оно не работает на некоторых машинах, таких как телефоны.
В 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 ( ^^
) всегда должен оценивать оба операнда. Это отличает его от других «логических» операторов, которые оценивают второй операнд только при необходимости. Я думаю, именно поэтому в Javascript нет «логического» xor, чтобы избежать путаницы.
Так что же должно произойти, если оба операнда ложные? Оба могут быть возвращены. Но только один может быть возвращен. Который из? Первый? Или второй? Моя интуиция подсказывает мне вернуть первые, но обычно «логические» операторы, вычисленные слева направо, и вернуть последнее оцененное значение. Или, может быть, массив, содержащий оба значения?
И если один операнд является правдивым, а другой - ложным, xor должен возвращать правдивый. Или, может быть, массив, содержащий истинный, чтобы сделать его совместимым с предыдущим случаем?
И, наконец, что должно произойти, если оба операнда истинны? Вы ожидаете чего-то ложного. Но нет никаких ложных результатов. Так что операция не должна ничего возвращать. Так может undefined
или .. пустой массив? Но пустой массив все еще правдив.
При использовании массива вы получите такие условия, как if ((a ^^ b).length !== 1) {
. Очень запутанно.
Преобразуйте значения в логическую форму, затем возьмите побитовый XOR. Это поможет и с не булевыми значениями.
Boolean(a) ^ Boolean(b)
есть ... вроде:
if( foo ? !bar : bar ) {
...
}
или проще читать:
if( ( foo && !bar ) || ( !foo && bar ) ) {
...
}
Зачем? Не знаю.
потому что разработчики javascript думали, что это будет ненужным, поскольку это может быть выражено другими, уже реализованными, логическими операторами.
вы также можете просто получить nand, вот и все, вы можете произвести впечатление на любую другую логическую операцию из этого.
Я лично думаю, что у него есть исторические причины, которые берут начало от языков синтаксиса на основе c, где, насколько мне известно, xor отсутствует или, по крайней мере, крайне необычен.
Да, просто сделай следующее. Предполагая, что вы имеете дело с логическими значениями 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 |
------------------------------------------
Наслаждаться.
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))
. Для логических значений «xy», 12, 4 и true
все являются истинными значениями, и их следует преобразовать в true
. так ("xy" XOR true)
должно быть false
, но ("xy" !== true)
вместо этого true
, как вы указываете. Так что !==
или !=
(оба) эквивалентны «логическому XOR» тогда и только тогда, когда вы преобразуете их аргументы в логические значения перед применением.
В приведенной выше функции XOR это приведет ПОДОБНОМУ результату, так как логический xor не совсем логический xor, означает, что это приведет к «false для равных значений» и «true для разных значений» с учетом соответствия типов данных.
Эта функция xor будет работать как фактический xor или логический оператор , это означает, что она будет иметь значение true или false в соответствии с передаваемыми значениями true или false . Используйте в соответствии с вашими потребностями
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)
отлично работает с логическими значениями. В машинописи + требуется, чтобы сделать его действительным !!(+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 для любых значений true / falsey, как если бы вы имели оператор в стандартных операторах 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.
Если вам не важен счет, или если вы заботитесь об оптимальной производительности: просто используйте побитовый 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
это просто оператор строгого неравенства .