Що означає "var FOO = FOO || {} "(Призначити змінну або порожній об'єкт цій змінній) означає в Javascript?


99

Дивлячись на вихідний код в Інтернеті, я натрапив на це у верхній частині кількох вихідних файлів.

var FOO = FOO || {};
FOO.Bar = …;

Але я поняття не маю, що || {}робить.

Я знаю {}, що дорівнює, new Object()і я думаю, що ||це щось на зразок "якщо воно вже існує, використовуйте його значення, тоді використовуйте новий об'єкт.

Чому я бачив би це у верхній частині вихідного файлу?


Примітка. Питання було відредаговано так, що це шаблон коду, який зазвичай можна побачити у верхній частині вихідних файлів Javascript.
Роберт Харві

Відповіді:


153

Ваша здогадка щодо наміру || {}досить близька.

Цей конкретний малюнок, коли його бачите у верхній частині файлів, використовується для створення простору імен , тобто іменованого об'єкта, під яким можна створювати функції та змінні без надмірного забруднення глобального об’єкта.

Причина , чому це використовується , так що якщо у вас є два (або більше) файлів:

var MY_NAMESPACE = MY_NAMESPACE || {};
MY_NAMESPACE.func1 = {
}

і

var MY_NAMESPACE = MY_NAMESPACE || {};
MY_NAMESPACE.func2 = {
}

обидва вони мають одне і те саме простір імен, але не має значення, в якому порядку завантажуються два файли, ви все одно отримаєте func1і func2правильно визначитеся в MY_NAMESPACEоб'єкті правильно.

Перший завантажений файл створить початковий MY_NAMESPACEоб’єкт, а будь-який файл, що завантажується згодом, об'єкт збільшить .

Корисно, це також дозволяє асинхронне завантаження сценаріїв, які мають одне і те саме простір імен, що може покращити час завантаження сторінки. Якщо <script>теги мають deferнабір атрибутів, ви не можете знати, в якому порядку вони будуть інтерпретовані, тому, як описано вище, ця проблема також вирішує цю проблему.


2
Це саме так, є пара js-файлів з точно такою ж декларацією на початку, велике спасибі!
Рікардо Санчес

41
+1 для читання між рядками та пояснення причин цього. Завжди добре, коли хтось дає відповідь, що користувач насправді хотів, а не лише той, про кого він попросив. :)
Спудлі

1
мені хочеться сказати, що це # ifndef / # визначити javascript :)
Даррен Копп

1
||також дуже корисно, коли ви хочете надати необов'язкові аргументи та ініціалізувати їх до значень за замовчуванням, якщо вони не передбачені:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
crazy2be

1
@ Crazy2be , що не працює , якщо за замовчуванням truthy, але значення falsey також правові, так як ||оператор не може сказати undefinedз falsey.
Альнітак

23
var AEROTWIST = AEROTWIST || {};

В основному цей рядок говорить про встановлення AEROTWISTзмінної на значення AEROTWISTзмінної або встановлення її на порожній об'єкт.

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

Тому, якщо AEROTWISTвже має значення, воно зберігатиметься як це значення, але якщо воно не було встановлено раніше, воно буде встановлене як порожній об'єкт.

це в основному те саме, що сказати це:

if(!AEROTWIST) {var AEROTWIST={};}

Сподіваюся, що це допомагає.


1
насправді сфера застосування буде добре у вашому останньому прикладі, оскільки JS не має блокової області
Alnitak

@Alnitak - мех, ти маєш рацію; Останнім часом я занадто багато працюю із закриттями і забув основи. Я відредагую відповідь.
Спудлі

6

Ще одне поширене використання для || є також встановити значення за замовчуванням для невизначеного параметра функції також:

function display(a) {
  a = a || 'default'; // here we set the default value of a to be 'default'
  console.log(a);
}

// we call display without providing a parameter
display(); // this will log 'default'
display('test'); // this will log 'test' to the console

Еквівалент в інших програмуваннях зазвичай:

function display(a = 'default') {
  // ...
}

Вам не потрібно varперед a, aвводить контекст виконання функції як формальний параметр , отже, це вже оголошено.
Fabrício Matté

6

Є дві основні частини, які var FOO = FOO || {};охоплює.

№1 Запобігання перекриттям

Уявіть, що ваш код розділений на кілька файлів, а ваші колеги також працюють над об'єктом, який називається FOO. Тоді це може призвести до того, що хтось уже визначив FOOі призначив йому функціональність (як skateboardфункція). Тоді ви перекривали б це, якби не перевіряли, чи він уже існує.

Проблемний випадок:

// Definition of co-worker "Bart" in "bart.js"
var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};

// Definition of co-worker "Homer" in "homer.js"
var FOO = {};

FOO.donut = function() {
  alert('I like donuts!');
};

У цьому випадку skateboardфункція пропаде , якщо ви завантажуєте файл JavaScript homer.jsпісля bart.jsв вашому HTML , тому що Гомер визначає новий FOOоб'єкт (і , таким чином , скасовує існуючу від Барта) , тому він знає тільки про donutфункції.

Тож вам потрібно використовувати, var FOO = FOO || {};що означає "FOO буде призначено FOO (якщо він вже існує) або новий порожній об'єкт (якщо FOO вже не існує).

Рішення:

var FOO = FOO || {};

// Definition of co-worker Bart in bart.js
FOO.skateboard = function() {
  alert('I like skateboarding!');
};

// Definition of co-worker Homer in homer.js
var FOO = FOO || {};

FOO.donut = function() {
  alert('I like donuts!');
};

Тому що Барт і Гомер тепер перевірка на існування , FOOперш ніж вони визначають свої методи, ви можете завантажити bart.jsі homer.jsв будь-якому порядку без перевизначення методів один одного (якщо вони мають різні назви). Таким чином, ви завжди отримаєте FOOоб'єкт, який має методи skateboardта donut(Так!).

№2 Визначення нового об’єкта

Якщо ви прочитали перший приклад, то вже тепер, яка мета цього || {}.

Тому що, якщо існуючого FOOоб'єкта немає, то ІЛИ-корпус активується та створює новий об’єкт, тож ви можете призначити йому функції. Подібно до:

var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};

3

Якщо в AEROTWIST немає значення або воно є нульовим або невизначеним, значення, присвоєне новому AEROTWIST, буде {} (порожній об'єкт)


1

||Оператор приймає два значення:

a || b

Якщо a truthy , воно повернеться a. Інакше воно повернеться b.

У falsy значення null, undefined, 0, "", NaNі false. Ціннісні значення - це все інше.

Отже, якщо aне було встановлено (чи це undefined), воно повернеться b.


Я не впевнений, що правду та фальси слід утримувати як фактичні слова. Забавно, але не зовсім стандартно. :-)
Орблінг

4
@Orbling вони досить часто використовуються для розмови про такі значення в JS.
Альнітак

+1 для опису оператора правильно, оскільки це не логічний оператор. Іноді його називають "оператором за замовчуванням".
Тім Бют

@Tim Єдина відмінність між ||JS (та Perl) та версією на C, C ++ та Java полягає в тому, що JS не приводить результат до булевого. Це все-таки логічний оператор.
Альнітак

@Alnitak: Можливо, через непрофесійний досвід розробників JS в минулому.
Орблінг

-1

Зауважте, що в деякій версії IE цей код не працюватиме, як очікувалося. Тому що varзмінна переосмислюється і призначається так - якщо я правильно пригадую проблему - у вас завжди з’явиться новий об’єкт. Це має вирішити проблему:

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