Что означает конструкция x = x || значит?

250

Я отлаживаю некоторый JavaScript, и не могу объяснить, что это ||делает?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

Может кто-нибудь дать мне подсказку, почему этот парень использует var title = title || 'ERROR'? Я иногда вижу это и без varдекларации.

opHASnoNAME
источник
44
Люди уже ответили на это ... но очень хорошо осознают тот факт, что второе значение выбирается, если первое значение falsy, а не просто undefined. Количество раз, которое я видел doWeDoIt = doWeDoIt || true, достаточно, чтобы заставить меня плакать. (то есть doWeDoItтеперь никогда не будет false)
Мэтт
4
Для тех, кто имеет опыт работы с C #, оператор двойной трубы эквивалентен оператору null-coalesce ??. Javascript оценивает ненулевые объекты, такие как true (или лучше оценивает нулевые объекты как ложные)
usr-local-ΕΨΗΕΛΩΝ
3
Не расстраивайтесь - JS - единственный тупой язык, который допускает это ужасное кодирование ... это и учит, что правильно вкладывать каждую функцию в строки кода и выбрасывать их, делая их одноразовыми и непригодными во второй раз. :) Я 30 лет на программировании и не буду трогать JS до тех пор, пока не сам, и я чувствую вашу боль, все, что я могу сказать, это держать под рукой «нет смысла, это только в JS», это единственный способ, которым я могу » мы получили! :)
Коллин
1
Пожалуйста, рассмотрите возможность изменения принятого ответа на мой ответ .
Михал Перлаковский

Ответы:

211

Это означает, что titleаргумент не является обязательным. Поэтому, если вы вызываете метод без аргументов, он будет использовать значение по умолчанию "Error".

Это сокращение для записи:

if (!title) {
  title = "Error";
}

Этот вид уловки с логическими выражениями также распространен в Perl. С выражением:

a OR b

он оценивает, trueесли либо, aлибо bесть true. Так что, если aэто правда, вам не нужно проверять bвообще. Это называется булевой оценкой короткого замыкания, поэтому:

var title = title || "Error";

в основном проверяет, titleоценивает ли false. Если это так, он «возвращается» "Error", в противном случае он возвращается title.

Клетус
источник
3
Извините, что разборчив, но аргумент не является обязательным, аргумент проверен
themightybun
4
Это НЕ ответ, и я согласен с последним комментарием, это даже не обязательно. Ни одна из частей этого ответа не верна, даже ссылка на Perl, поскольку оператор Perl фактически делает SENSE и оценивается совершенно по-другому. JS более эффективен в гораздо более «преобразованном» методе логической логики, который я нахожу гораздо более запутанным для чтения / записи. Ответ ниже под названием «Что такое оператор двойной трубы» на самом деле является правильным ответом.
Коллин
198

Что такое оператор двойной трубы ( ||)?

Оператор двойной трубы ( ||) является логическим ORоператором . На большинстве языков это работает следующим образом:

  • Если первое значение false, оно проверяет второе значение. Если это так true, он возвращается, trueи если это так false, он возвращается false.
  • Если первое значение true, оно всегда возвращается true, независимо от того, какое второе значение.

Так что в основном это работает как эта функция:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

Если вы все еще не понимаете, посмотрите на эту таблицу:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

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

Чем он отличается в JavaScript?

JavaScript немного отличается, потому что это слабо типизированный язык . В этом случае это означает, что вы можете использовать ||оператор со значениями, которые не являются логическими. Хотя это не имеет смысла, вы можете использовать этот оператор, например, с функцией и объектом:

(function(){}) || {}

Что там происходит?

Если значения не являются логическими, JavaScript делает неявное преобразование в логические . Это означает , что если значение falsey (например 0, "", null, undefined(смотри также все значения falsey в JavaScript )), это будет рассматриваться как false; в противном случае это рассматривается как true.

Так что приведенный выше пример должен дать true, потому что пустая функция верна. Ну, это не так. Возвращает пустую функцию. Это потому, что ||оператор JavaScript не работает, как я писал в начале. Работает следующим образом:

  • Если первое значение равно Falsey , оно возвращает второе значение .
  • Если первое значение верно , оно возвращает первое значение .

Удивлены? На самом деле, он «совместим» с традиционным ||оператором. Это можно записать как следующую функцию:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

Если вы передаете истинное значение как x, оно возвращает x, то есть истинное значение. Так что, если вы используете его позже в ifпункте:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

Вы получаете "Either x or y is truthy.".

Если бы xбыл фальсей, eitherXorYбыл бы y. В этом случае вы получите , "Either x or y is truthy."если yбыл truthy; в противном случае вы получите "Neither x nor y is truthy".

Актуальный вопрос

Теперь, когда вы знаете, как ||работает оператор, вы, вероятно, сможете сами разобраться, что это x = x || yзначит. Если xправдиво, xназначено x, так что на самом деле ничего не происходит; в противном случае yназначается x. Обычно используется для определения параметров по умолчанию в функциях. Тем не менее, это часто считается плохой практикой программирования , потому что она не позволяет вам передавать значение Фальси (что не обязательно undefinedили null) в качестве параметра. Рассмотрим следующий пример:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Это выглядит актуально с первого взгляда. Тем не менее, что произойдет, если вы передадите в falseкачестве flagAпараметра (поскольку это логическое значение, т. Е. Может быть trueили false)? Это стало бы true. В этом примере нет способа установить flagAзначение false.

Лучше было бы явно проверить, flagAесть ли undefined, вот так:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Хотя он длиннее, он всегда работает и его легче понять.


Вы также можете использовать синтаксис ES6 для параметров функций по умолчанию , но учтите, что он не работает в старых браузерах (например, IE). Если вы хотите поддерживать эти браузеры, вы должны перенести свой код с Babel .

Смотрите также Логические операторы на MDN .

Михал Перлаковский
источник
13
+1 - безусловно самый правильный и полный ответ. И для тех, у кого есть этот вопрос (включая некоторых из нас, ветеранов-программистов, плохо знакомых с JS), безусловно, следует сосредоточить все усилия на этом ответе в этой строке: «Хотя это не имеет смысла», потому что этот «набранный Лоусли» просто никогда не будет иметь смысла для тех из нас, кто вырос без него. Для нас логический оператор - это всего лишь ТОЛЬКО ...... и кто бы то ни думал, что было бы неплохо остановиться и подумать о каком-то дурацком преобразовании небулевых значений в логические при чтении / записи кода. забыл принять их лекарства в тот день! :)
Коллин
2
+1, в двух словах: title = title || 'Error'значитif (title) { title = title; } else { title = 'Error'; }
Андре Элрико
Я на самом деле не согласен с линией «хотя это не имеет смысла». Я понимаю, что строка не будет компилироваться, например, в C, но она хорошо понятна, если вы пришли, например, из Ruby или даже Groovy. В Ruby это можно выразить еще короче, как title ||= 'Error'.
Эллиот Нельсон
28

Если заголовок не установлен, используйте «ОШИБКА» в качестве значения по умолчанию.

Более общий:

var foobar = foo || default;

Читает: Установите Foobar в fooили default. Вы могли бы даже связать это много раз:

var foobar = foo || bar || something || 42;
ericteubert
источник
1
Я нашел это запутанным, потому что переменные имеют одинаковое имя. Гораздо проще, когда они этого не делают.
Норберт Норбертсон
14

Объясняя это немного больше ...

||Оператор является логико - orоператор. Результат верен, если первая часть верна, и истина, если вторая часть верна, и истина, если обе части верны. Для наглядности вот оно в таблице:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

Теперь заметить что-то здесь? Если Xэто правда, результат всегда верно. Так что, если мы знаем, что Xэто правда, нам вообще не нужно проверять Y. Таким образом, во многих языках реализованы оценщики «короткого замыкания» для логического or(и логического and- другого направления). Они проверяют первый элемент, и если это правда, они вообще не проверяют второй элемент. Результат (в логическом выражении) тот же, но с точки зрения исполнения потенциально огромная разница, если второй элемент дорог для вычисления.

Так какое это имеет отношение к вашему примеру?

var title   = title || 'Error';

Давайте посмотрим на это. titleЭлемент передается в вашей функции. В JavaScript, если вы не передаете параметр, по умолчанию используется нулевое значение. Также в JavaScript, если ваша переменная имеет нулевое значение, логические операторы считают ее ложной. Поэтому, если эта функция вызывается с заданным заголовком, это не ложное значение и, таким образом, присваивается локальной переменной. Однако, если ему не дано значение, оно является нулевым значением и, следовательно, ложным. Затем логический orоператор вычисляет второе выражение и возвращает вместо него «Ошибка». Теперь локальной переменной присвоено значение «Ошибка».

Это работает из-за реализации логических выражений в JavaScript. Он не возвращает правильное логическое значение ( trueили false), но вместо этого возвращает значение, которое ему было дано согласно некоторым правилам относительно того, что считается эквивалентным trueи что считается эквивалентным false. Посмотрите свою ссылку на JavaScript, чтобы узнать, что JavaScript считает истинным или ложным в логических контекстах.

ПРОСТО МОЕ правильное мнение
источник
8

Двойная труба обозначает логическое «ИЛИ». Это не совсем тот случай, когда «параметр не установлен», так как строго в javascript, если у вас есть такой код:

function foo(par) {
}

Тогда звонки

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

не эквивалентны.

Двойная труба (||) приведёт первый аргумент к логическому значению, и, если полученное логическое значение истинно, выполните присваивание, иначе назначит правильную часть.

Это имеет значение, если вы проверите для неустановленного параметра.

Допустим, у нас есть функция setSalary, у которой есть один необязательный параметр. Если пользователь не предоставляет параметр, то следует использовать значение по умолчанию 10.

если вы делаете проверку, как это:

function setSalary(dollars) {
    salary = dollars || 10
}

Это даст неожиданный результат по вызову, как

setSalary(0) 

Это все еще установит 10, следуя описанному выше потоку.

Juriy
источник
8

В основном это проверяет, если значение перед || оценивается как true, если да, он принимает это значение, если нет, он принимает значение после ||.

Значения, для которых он будет принимать значение после || (насколько я помню):

  • не определено
  • ложный
  • 0
  • '' (Нулевая или Нулевая строка)
Morfildur
источник
1
ложь || ноль || undefined || 0 || '' || «Вы забыли
ноль
7

Хотя ответ Cletus верен, я чувствую, что нужно добавить больше подробностей в отношении «оценивается как ложное» в JavaScript.

var title = title || 'Error';
var msg   = msg || 'Error on Request';

Это не просто проверка наличия заголовка / сообщения, но также и фальсификации любого из них . то есть одно из следующего:

  • ложный.
  • 0 (ноль)
  • "" (пустая строка)
  • ноль.
  • не определено.
  • NaN (специальное числовое значение, означающее не число!)

Так в линии

var title = title || 'Error';

Если title является правдивым (то есть не ложным, поэтому title = "titleMessage" и т. Д.), То логический оператор OR (||) нашел одно значение 'true', что означает, что он оценивается как true, поэтому он замыкается и возвращает истинное значение (название).

Если title является ложным (то есть одним из списка выше), тогда логический оператор OR (||) нашел значение «false» и теперь должен оценить другую часть оператора, «Error», которая оценивается как true и, следовательно, возвращается.

Также может показаться (после некоторых быстрых экспериментов с консолью firebug), что обе стороны оператора оценивают как false, он возвращает второй оператор 'ложь'.

т.е.

return ("" || undefined)

возвращает undefined, возможно, это позволяет вам использовать поведение, о котором идет речь в этом вопросе, при попытке установить заголовок / сообщение по умолчанию в "". т.е. после бега

var foo = undefined
foo = foo || ""

Foo будет установлен на ""

Azrantha
источник
5

оператор двойной трубы

этот пример полезен?

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

так же может быть

var section = document.getElementById('special') || document.getElementById('main');
Choise
источник
4

Чтобы добавить некоторые объяснения ко всему сказанному до меня, приведу несколько примеров для понимания логических понятий.

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

Это означает, что если левая сторона оценена как истинная инструкция, она будет завершена, а левая сторона будет возвращена и присвоена переменной. в других случаях правая сторона будет возвращена и назначена.

И оператор имеет противоположную структуру, как показано ниже.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh
Мохсен Ализаде
источник
3

|| является логическим оператором ИЛИ Как и в JavaScript, undefined, null, 0, false считаются ложными значениями.

Это просто значит

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"
Шиванг Гупта
источник
2

Цитата: «Что означает конструкция x = x || y?»

Назначение значения по умолчанию.

Это означает предоставление значения по умолчанию от y до x , если x все еще ожидает своего значения, но еще не получил его или был намеренно опущен, чтобы вернуться к значению по умолчанию.

Беким Бакай
источник
Это точное значение конструкции и единственное ее значение. И это было в значительной степени подпрограммой при написании функций, которые можно было получить в виде прототипов, автономных функций, а также в качестве заимствованных методов для применения к другому элементу. Где его основной и единственной обязанностью было изменить ссылку на цель. Пример: function getKeys(x) { x = x || this ; .... }который может быть использован без модификации в качестве отдельной функции, как метод свойства в прототипах и как метод элемента, который может получить другой элемент в качестве аргумента в виде `[element] .getKeys (anotherElement);`
Bekim Bacaj
-5

И я должен добавить еще одну вещь: эта стенография - мерзость. Это неправильно использует случайную оптимизацию интерпретатора (не заботясь о второй операции, если первая верна), чтобы управлять назначением. Это использование не имеет ничего общего с целью оператора. Я не верю, что это должно когда-либо использоваться.

Я предпочитаю троичный оператор для инициализации, например,

var title = title?title:'Error';

Это использует однострочную условную операцию для ее правильного назначения. Он все еще играет неприглядные игры с правдивостью, но это Javascript для вас.

tqwhite
источник