Що означає конструкція x = x || y означає?


250

Я налагоджую деякі JavaScript, і не можу пояснити, що це ||робить?

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

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


44
Люди вже відповіли на це ... але бути надзвичайно обізнаними з тим фактом, що друге значення вибирається, якщо перше значення є falsy, а не СПОСОБ undefined. Кількість разів, яку я бачила doWeDoIt = doWeDoIt || true, достатня, щоб змусити мене плакати. (тобто doWeDoItтепер ніколи не буде false)
Метт


4
Для тих, хто має досвід роботи з C #, оператор з двома трубами еквівалентний оператору нульового злиття ??. Javascript оцінює ненульові об’єкти типу true (або краще оцінює нульові об’єкти на хибні)
usr-local-ΕΨΗΕΛΩΝ

3
Не відчувайте себе погано - JS - єдина гуфна мова, що дозволяє це жахливе кодування .... це і вчити, що правильно вкладати кожну функцію в рядки коду і викидати їх, роблячи їх одноразовими і непридатними для використання вдруге. :) Я кодую 30 років, і не дуже давно торкаюся до JS, і я відчуваю, що ти болиш, все, що я можу сказати, - тримати "немає сенсу, це лише в JS" cheetshey handy - це єдиний спосіб, який я " я потрапив! :)
Collin Chaffin

1
Будь ласка, подумайте про зміну прийнятої відповіді на мою відповідь .
Michał Perłakowski

Відповіді:


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 є eval у набагато більш "перетвореному" булевому логічному методі, який я також вважаю набагато більш заплутаним для читання / запису. Відповідь нижче під назвою "Що таке оператор з двома трубами" - це насправді правильна відповідь.
Collin Chaffin

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 не працює, як я писав на початку. Це працює наступним чином:

  • Якщо перше значення - фальси , воно повертає друге значення .
  • Якщо перше значення є truthy , воно повертає перше значення .

Здивувались? Насправді це "сумісно" з традиційним ||оператором. Він може бути записаний у такий спосіб:

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

Якщо ви передаєте значення truthy як x, воно повертає x, тобто значення truthy. Тож якщо ви використовуєте його пізніше в 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було неправдою; інакше ти отримаєш "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), безумовно, слід зосередити увагу на всій цій відповіді на цьому рядку: "Хоча це не має сенсу", тому що цей "набраний лайлі" просто ніколи не матиме сенсу тим із нас, що виросли без цього. Для нас булевий оператор - це саме те і ТОЛЬКІ що ...... і хто-небудь коли-небудь думав, що було б гарною ідеєю зупинитись і продумати якесь дурне перетворення не булевих значень в булеві під час читання / запису коду , забув взяти їхні ліки того дня! :)
Collin Chaffin

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;

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)

не рівнозначні.

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

Це має значення, якщо ви перевіряєте на невстановлений параметр.

Скажімо, у нас є функція setSalary, яка має один необов'язковий параметр. Якщо користувач не надає параметр, слід використовувати значення за замовчуванням 10.

якщо ви зробите чек так:

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

Це дасть несподіваний результат на зразок дзвінка

setSalary(0) 

Він все одно встановить 10 за потоком, описаним вище.


8

В основному він перевіряє, чи є значення перед || оцінюється як true, якщо так, то воно приймає це значення, якщо ні, воно приймає значення після ||

Значення, для яких воно прийме значення після || (наскільки я пам’ятаю):

  • невизначений
  • помилковий
  • 0
  • '' (Null або Null string)

1
помилкові || null || невизначений || 0 || '' || 'ти забув нуль'
Dziamid

7

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

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

Це не лише перевірка того, чи вказано заголовок / msg, але також чи одна з них є хибною . тобто одне з наступних:

  • помилковий.
  • 0 (нуль)
  • "" (порожній рядок)
  • нуль.
  • невизначений.
  • NaN (спеціальне значення числа, яке означає Не-число)!

Тож у рядку

var title = title || 'Error';

Якщо заголовок truthy (тобто не хибний, тому title = "titleMessage" тощо), то булевий оператор OR (||) знайшов одне значення "true", що означає, що воно оцінює як істинне, тому воно коротке замикання і повернення справжнє значення (назва).

Якщо заголовок є хибним (тобто одним із списку вище), то булевий АБО (||) оператор знайшов значення "помилкового", і тепер потрібно оцінити іншу частину оператора "Помилка", яка оцінюється як істинна , а відтак повертається.

Здавалося б, (після швидкого експерименту з консолью firebug), якщо обидві сторони оператора оцінюють значення false, він повертає другий оператор "хибного".

тобто

return ("" || undefined)

повертається невизначено, це, ймовірно, дозволить вам використовувати поведінку, про яку йдеться у цьому питанні, намагаючись назву / повідомлення за замовчуванням на "". тобто після бігу

var foo = undefined
foo = foo || ""

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


5

оператор з двома трубами

цей приклад корисний?

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

також може бути

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

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, не визначене, NULL, 0, помилково вважаються falsy значеннями.

Це просто означає

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 ; .... }який може бути використаний без змін як окрема функція, як метод властивості в прототипах і як метод елемента, який може отримати інший елемент як його аргумент як `[елемент] .getKeys (AnotherElement);`
Бекім Бакай

-5

І я мушу додати ще одне: цей шматок скорочень - це гидота. Він зловживає випадковою оптимізацією інтерпретатора (не турбуючись при другій операції, якщо перша є правдоподібною) для управління завданням. Це використання не має нічого спільного з метою оператора. Я не вірю, що його колись слід використовувати.

Я віддаю перевагу потрійному оператору для ініціалізації, наприклад,

var title = title?title:'Error';

При цьому використовується однолінійна умовна операція для свого правильного призначення. Він все ще грає в непривабливі ігри з правдивістю, але це Javascript для вас.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.