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


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

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

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

11 174

11 ответов:

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

это стенография для записи:

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

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

a OR b

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

var title = title || "Error";

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

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

оператор двойной трубы (||) является логическое 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 делает неявный разговор в boolean. Это означает, что если значение falsey (например 0,"",null,undefined (см. Также все ложные значения в 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 был falsey, eitherXorY будет y. В этом случае вы получите "Either x or y is truthy." если y было правдиво; в противном случае вы получите "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). Если вы хотите поддерживать эти браузеры, вы должны транспилировать свой код с помощью Бабель.

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

Если заголовок не задан, используйте 'ERROR' в качестве значения по умолчанию.

более общий:

var foobar = foo || default;

читает: установите foobar в foo или default. Вы можете даже цепочку это много раз:

var foobar = foo || bar || something || 42;

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

The || оператор логического-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 оператор затем вычисляет второе выражение и возвращает 'Error' вместо. Так что теперь локальной переменной присваивается значение 'Error'.

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

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

function foo(par) {
}

вызывает

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

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

Double pipe ( | | ) приведет первый аргумент к boolean, и если результирующее boolean истинно - выполните назначение, иначе он назначит правую часть.

это имеет значение, если вы проверяете для параметра unset.

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

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

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

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

setSalary(0) 

Он все равно установит 10 после потока, описанного выше.

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

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

  • неопределено
  • ложные
  • 0
  • " (нулевая или нулевая строка)

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

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

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

можно

var section = document.getElementById('special') || document.getElementById('main');

пока Клетус' ответ правильно, я чувствую, что более подробно следует добавить в отношении "оценивает ложь" в JavaScript.

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

не просто проверяет, если заголовок/msg был предоставлен, но и если любой из них ложь. т. е. одно из следующих действий:

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

в строку

var title = title || 'Error';

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

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

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

т. е.

return ("" || undefined)

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

var foo = undefined
foo = foo || ""

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

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

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

присвоение значения по умолчанию.

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

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

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

var title = title?title:'Error';

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