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

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

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

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

11 ответов


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

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

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

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

a OR b

он оценивает в true если a или b is 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  

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

как это отличается в JavaScript?

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

(function(){}) || {}

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

если значения не являются логическими, JavaScript делает неявный разговор с boolean. Это означает, что если значение 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 был falsey, eitherXorY будет y. В этом случае вы получите "Either x or y is truthy." если y было правдой; иначе вы бы получили "Neither x nor y is truthy".

вопрос

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

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

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

было бы лучше явно проверьте, является ли flagA is 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;

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

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

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

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

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

var title   = title || 'Error';

давайте посмотрим на это. The title элемент передано вашей функции. В JavaScript, если вы не передаете параметр, он по умолчанию имеет значение null. Также в JavaScript, если ваша переменная является нулевым значением, логические операторы считают ее ложной. Поэтому, если эта функция вызывается с заданным заголовком, Это значение не является ложным и, таким образом, присваивается локальной переменной. Если, однако, ему не задано значение, это значение null и, следовательно, false. Логико-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, если да, оно принимает это значение, если нет, оно принимает значение после ||.

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

  • undefined
  • false
  • 0
  • "(нулевая или нулевая строка)

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

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

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

можно

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

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

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

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

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

в строку

var title = title || 'Error';

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

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

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

то есть

return ("" || undefined)

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

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 для вас.