Co znaczy „var FOO = FOO || {} ”(Przypisanie zmiennej lub pustego obiektu do tej zmiennej) oznacza w JavaScript?

99

Patrząc na kod źródłowy online, natknąłem się na to na początku kilku plików źródłowych.

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

Ale nie mam pojęcia, co || {}robi.

Wiem, że {}jest równe new Object()i myślę, że ||jest to coś w stylu „jeśli już istnieje, użyj jego wartości, w przeciwnym razie użyj nowego obiektu.

Dlaczego miałbym to widzieć na początku pliku źródłowego?

Ricardo Sanchez
źródło
Uwaga: pytanie zostało zredagowane, aby odzwierciedlić, że jest to wzorzec kodu powszechnie występujący na początku plików źródłowych Javascript.
Robert Harvey

Odpowiedzi:

153

Twoje przypuszczenie co do zamiaru || {}jest dość bliskie.

Ten szczególny wzorzec, widziany na górze plików, jest używany do tworzenia przestrzeni nazw , tj. Nazwanego obiektu, w którym można tworzyć funkcje i zmienne bez nadmiernego zanieczyszczania obiektu globalnego.

Powód, dla którego jest używany, jest taki, że jeśli masz dwa (lub więcej) pliki:

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

i

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

z których oba mają tę samą przestrzeń nazw, wtedy nie ma znaczenia, w jakiej kolejności oba pliki są ładowane, nadal poprawnie otrzymujesz func1i func2poprawnie zdefiniujesz w MY_NAMESPACEobiekcie.

Pierwszy załadowany plik utworzyMY_NAMESPACE obiekt początkowy , a każdy później załadowany plik rozszerzy obiekt.

Przydatnie, pozwala to również na asynchroniczne ładowanie skryptów, które mają tę samą przestrzeń nazw, co może skrócić czas ładowania strony. Jeśli <script>tagi mają deferustawiony atrybut, nie możesz wiedzieć, w jakiej kolejności będą interpretowane, więc jak opisano powyżej, rozwiązuje to również ten problem.

Alnitak
źródło
2
Tak właśnie jest, jest kilka plików js z dokładnie taką samą deklaracją na początku, wielkie dzięki!
Ricardo Sanchez
41
+1 za czytanie między wierszami i wyjaśnianie powodów takiego działania. Zawsze dobrze jest, gdy ktoś udziela odpowiedzi, której użytkownik faktycznie chciał, a nie tylko tej, o którą prosił. :)
Spudley
1
lubię powiedzieć, że to # ifndef / # define dla javascript :)
Darren Kopp
1
||jest również bardzo przydatny, gdy chcesz podać opcjonalne argumenty i zainicjować je do wartości domyślnych, jeśli nie zostaną podane:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
crazy2be
1
@ crazy2be że nie działa, jeśli domyślnie truthy, ale również wartości falsey są legalne, ponieważ ||operator nie może powiedzieć undefinedz falsey.
Alnitak
23
var AEROTWIST = AEROTWIST || {};

Zasadniczo ten wiersz mówi, że ustaw AEROTWISTzmienną na wartość AEROTWISTzmiennej lub ustaw ją na pusty obiekt.

Podwójna kreska ||to instrukcja OR, a druga część OR jest wykonywana tylko wtedy, gdy pierwsza część zwróci fałsz.

Dlatego jeśli AEROTWISTjuż ma wartość, zostanie zachowana jako ta wartość, ale jeśli nie została wcześniej ustawiona, zostanie ustawiona jako pusty obiekt.

to w zasadzie to samo, co powiedzenie tego:

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

Mam nadzieję, że to pomoże.

Spudley
źródło
1
w rzeczywistości zakres byłby w porządku w twoim ostatnim przykładzie, ponieważ JS nie ma zakresu blokowego
Alnitak
@Alnitak - meh, masz rację; Ostatnio za dużo pracowałem z zamknięciami i zapomniałem o podstawach. Zmienię odpowiedź.
Spudley
6

Inne powszechne zastosowanie || jest również ustawienie wartości domyślnej dla niezdefiniowanego parametru funkcji:

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

Odpowiednik w innych programach zwykle to:

function display(a = 'default') {
  // ...
}
alessioalex
źródło
Nie trzeba varprzed a, awprowadza kontekst wykonania funkcji jako parametr formalny , dlatego jest już zadeklarowany.
Fabrício Matté,
6

Istnieją dwie główne części, które var FOO = FOO || {};obejmują.

# 1 Zapobieganie zastąpieniom

Wyobraź sobie, że Twój kod jest podzielony na wiele plików, a Twoi współpracownicy również pracują nad obiektem o nazwie FOO. Wówczas mogłoby to doprowadzić do przypadku, że ktoś już zdefiniował FOOi przypisał mu funkcjonalność (np. skateboardFunkcję). Wtedy nadpisałbyś go, gdybyś nie sprawdzał, czy już istnieje.

Problematyczny przypadek:

// 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!');
};

W tym przypadku skateboardfunkcja zniknie, jeśli załadujesz plik JavaScript homer.jspóźniej bart.jsw swoim HTML, ponieważ Homer definiuje nowy FOOobiekt (i tym samym zastępuje istniejący z Bartka), więc wie tylko o donutfunkcji.

Musisz więc użyć, var FOO = FOO || {};co oznacza „FOO zostanie przypisany do FOO (jeśli już istnieje) lub nowego pustego obiektu (jeśli FOO jeszcze nie istnieje).

Rozwiązanie:

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!');
};

Ponieważ Bart i Homer sprawdzają teraz istnienie FOOmetod, zanim zdefiniują swoje metody, możesz załadować bart.jsi homer.jsw dowolnej kolejności bez zastępowania metod innych (jeśli mają różne nazwy). Więc zawsze otrzymasz FOOobiekt, który ma metody skateboardi donut(Yay!).

# 2 Definiowanie nowego obiektu

Jeśli przeczytałeś pierwszy przykład, to już teraz wiesz, jaki jest cel || {}.

Ponieważ jeśli nie ma istniejącego FOOobiektu, przypadek OR stanie się aktywny i utworzy nowy obiekt, dzięki czemu możesz przypisać do niego funkcje. Lubić:

var FOO = {};

FOO.skateboard = function() {
  alert('I like skateboarding!');
};
Benny Neugebauer
źródło
3

Jeśli nie ma wartości w AEROTWIST lub jest ona pusta lub nieokreślona, ​​wartość przypisana do nowego AEROTWIST będzie {} (pusty obiekt)

sudipto
źródło
1

||Użytkownik pobiera dwie wartości:

a || b

Jeśli a jest prawdą , wróci a. W przeciwnym razie wróci b.

Wartości falsy są null, undefined, 0, "", NaNi false. Prawdziwe wartości to wszystko inne.

Więc jeśli anie został ustawiony (czy to jest undefined), zwróci b.

pimvdb
źródło
Nie jestem pewien, czy prawda i fałsz powinny być utrwalane jako prawdziwe słowa. Zabawne, ale nie do końca standardowe. :-)
Orbling
4
@Orbling są dość często używane do mówienia o takich wartościach w JS.
Alnitak
+1 za prawidłowe opisanie operatora, ponieważ nie jest to operator logiczny. Czasami nazywa się to „operatorem domyślnym”.
Tim Büthe
@Tim Jedyną różnicą między ||JS (i Perlem) a wersją w C, C ++ i Javie jest to, że JS nie rzutuje wyniku na wartość logiczną. To wciąż operator logiczny.
Alnitak
@Alnitak: Prawdopodobnie ze względu na nieprofesjonalne doświadczenie programistów JS w przeszłości.
Orbling
-1

Zauważ, że w niektórych wersjach IE ten kod nie będzie działał zgodnie z oczekiwaniami. Ponieważ varzmienna jest przedefiniowana i przypisana, więc - jeśli dobrze pamiętam problem - zawsze będziesz mieć nowy obiekt. To powinno rozwiązać problem:

var AEROTWIST;
AEROTWIST = AEROTWIST || {};
ZER0
źródło