Что означает «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 за чтение между строк и объяснение причин этого. Всегда хорошо, когда кто-то дает ответ, который действительно хочет пользователь, а не только тот, который он просил. :)
Spudley
1
Я люблю говорить, что это # ​​ifndef / # определение для javascript :)
Даррен Копп,
1
||также действительно полезен, если вы хотите предоставить необязательные аргументы и инициализировать их значениями по умолчанию, если они не function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
указаны
1
@ crazy2be, который не работает, если значение по умолчанию правдиво, но ложные значения также допустимы, поскольку ||оператор не может определить undefinedот falsey.
Alnitak
23
var AEROTWIST = AEROTWIST || {};

В основном эта строка говорит, что установите AEROTWISTпеременную на значение AEROTWISTпеременной или установите ее на пустой объект.

Двойной канал ||- это оператор ИЛИ, а вторая часть ИЛИ выполняется только в том случае, если первая часть возвращает ложь.

Следовательно, если AEROTWISTуже есть значение, оно будет сохранено как это значение, но если оно не было установлено ранее, оно будет установлено как пустой объект.

это в основном то же самое, что сказать следующее:

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

Надеюсь, это поможет.

Spudley
источник
1
на самом деле область видимости была бы хороша в вашем последнем примере, потому что JS не имеет области видимости блока
Альнитак
@Alnitak - ты прав; В последнее время я слишком много работал с замыканиями и забыл основы. Отредактирую ответ.
Spudley
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объекта, тогда OR-case станет активным и создаст новый объект, поэтому вы можете назначить ему функции. Подобно:

var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};
Бенни Нойгебауэр
источник
3

Если в AEROTWIST нет значения или оно равно нулю или не определено, значение, присвоенное новому AEROTWIST, будет {} (пустой объект)

Sudipto
источник
1

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

a || b

Если a истинно , оно вернется a. В противном случае он вернется b.

В falsy значения null, undefined, 0, "", NaNи false. Истинные ценности - это все остальное.

Так что, если aон не был установлен (это так undefined), он вернется b.

pimvdb
источник
Я не уверен, что истина и ложь должны быть увековечены как настоящие слова. Забавно, но не совсем стандартно. :-)
Orbling
4
@Orbling они довольно часто используются для обсуждения таких значений в JS.
Alnitak
+1 для правильного описания оператора, так как это не логический оператор. Иногда его называют «оператором по умолчанию».
Tim Büthe
@Tim Единственная разница между ||JS (и Perl) и версией в C, C ++ и Java заключается в том, что JS не приводит результат к логическому. Это по-прежнему логический оператор.
Alnitak
@Alnitak: Возможно, из-за непрофессионального опыта JS-разработчиков в прошлом.
Orbling
-1

Обратите внимание, что в некоторых версиях IE этот код работает не так, как ожидалось. Поскольку var, переменная переопределяется и назначается, поэтому - если я правильно помню проблему - у вас всегда будет новый объект. Это должно решить проблему:

var AEROTWIST;
AEROTWIST = AEROTWIST || {};
ZER0
источник