O que significa “var FOO = FOO || {} ”(Atribuir uma variável ou um objeto vazio a essa variável) significa em Javascript?

99

Olhando para um código-fonte online, encontrei isso no topo de vários arquivos-fonte.

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

Mas não tenho ideia do que || {}seja.

Eu sei que {}é igual a new Object()e acho que ||é para algo como "se já existir use o valor, caso contrário, use o novo objeto.

Por que eu veria isso no topo de um arquivo de origem?

Ricardo Sanchez
fonte
Observação: a pergunta foi editada para refletir que este é um padrão de código comumente visto na parte superior dos arquivos de origem Javascript.
Robert Harvey

Respostas:

153

Seu palpite quanto à intenção de || {}está bem próximo.

Este padrão particular, quando visto no topo dos arquivos, é usado para criar um namespace , ou seja, um objeto nomeado sob o qual funções e variáveis ​​podem ser criadas sem poluir indevidamente o objeto global.

O motivo pelo qual é usado é que, se você tiver dois (ou mais) arquivos:

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

e

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

ambos compartilham o mesmo namespace, então não importa a ordem em que os dois arquivos são carregados, você ainda obtém func1e func2define corretamente dentro do MY_NAMESPACEobjeto.

O primeiro arquivo carregado criará o MY_NAMESPACEobjeto inicial e qualquer arquivo carregado subsequentemente aumentará o objeto.

De forma útil, isso também permite o carregamento assíncrono de scripts que compartilham o mesmo namespace, o que pode melhorar o tempo de carregamento da página. Se as <script>tags tiverem o deferatributo definido, você não poderá saber em que ordem serão interpretadas, portanto, conforme descrito acima, isso também corrige o problema.

Alnitak
fonte
2
Este é exatamente o caso, há alguns arquivos js com exatamente a mesma declaração no início, muito obrigado!
Ricardo Sanchez
41
1 para ler nas entrelinhas e explicar as razões para fazê-lo. É sempre bom quando alguém dá a resposta que o usuário realmente queria, e não apenas aquela que ele pediu. :)
Spudley de
1
gosto de dizer que é o # ifndef / # define for javascript :)
Darren Kopp
1
||também é muito útil quando você deseja fornecer argumentos opcionais e inicializá-los com os padrões se não forem fornecidos:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
crazy2be
1
@ crazy2be que não funciona se o padrão é truthy, mas os valores Falsey também são legais, desde que o ||operador não pode dizer undefineda partir falsey.
Alnitak
23
var AEROTWIST = AEROTWIST || {};

Basicamente, esta linha diz para definir a AEROTWISTvariável para o valor da AEROTWISTvariável ou para um objeto vazio.

O pipe duplo ||é uma instrução OR e a segunda parte do OR só é executada se a primeira parte retornar falso.

Portanto, se AEROTWISTjá tiver um valor, ele será mantido com esse valor, mas se não tiver sido definido antes, será definido como um objeto vazio.

é basicamente o mesmo que dizer isto:

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

Espero que ajude.

Spudley
fonte
1
na verdade, o escopo estaria bem em seu último exemplo porque JS não tem escopo de bloco
Alnitak
@Alnitak - meh, você está certo; Tenho trabalhado muito com tampas ultimamente e esqueci o básico. Vou editar a resposta.
Spudley de
6

Outro uso comum para || é definir um valor padrão para um parâmetro de função indefinido também:

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

O equivalente em outra programação geralmente é:

function display(a = 'default') {
  // ...
}
alessioalex
fonte
Você não precisa varem frente a, aentra contexto de execução da função como um parâmetro formal , portanto, já está declarado.
Fabrício Matté
6

Existem duas partes principais que var FOO = FOO || {};cobrem.

# 1 Prevenção de substituições

Imagine que você tem seu código dividido em vários arquivos e seus colegas de trabalho também estão trabalhando em um objeto chamado FOO. Então, isso pode levar ao caso de alguém já ter definido FOOe atribuído uma funcionalidade a ele (como uma skateboardfunção). Em seguida, você o substituiria, se não estivesse verificando se ele já existe.

Caso problemático:

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

Nesse caso, a skateboardfunção desaparecerá se você carregar o arquivo JavaScript homer.jsdepois bart.jsem seu HTML, porque Homer define um novo FOOobjeto (e, portanto, substitui o existente de Bart), então ele só sabe sobre a donutfunção.

Portanto, você precisa usar o var FOO = FOO || {};que significa "FOO será atribuído a FOO (se já existir) ou um novo objeto em branco (se FOO ainda não existir).

Solução:

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

Como Bart e Homer agora estão verificando a existência de FOOantes de definirem seus métodos, você pode carregar bart.jse homer.jsem qualquer ordem, sem substituir os métodos um do outro (se eles tiverem nomes diferentes). Assim, você sempre obterá um FOOobjeto que possui os métodos skateboarde donut(Yay!).

# 2 Definindo um novo objeto

Se você leu o primeiro exemplo, então sabe qual é o propósito do || {}.

Porque se não houver nenhum FOOobjeto existente , o caso OR se tornará ativo e criará um novo objeto, para que você possa atribuir funções a ele. Gostar:

var FOO = {};

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

Se não houver valor em AEROTWIST ou for nulo ou indefinido, o valor atribuído ao novo AEROTWIST será {} (um objeto em branco)

Sudipto
fonte
1

O ||operador assume dois valores:

a || b

Se um for verdadeiro , ele retornará a. Caso contrário, ele retornará b.

Os valores Falsas são null, undefined, 0, "", NaNe false. Os valores verdadeiros são todo o resto.

Portanto, se anão foi definido (é undefined), ele retornará b.

pimvdb
fonte
Eu não tenho certeza truthy e Falsey deve ser perpetuada como palavras reais. Divertido, mas não exatamente padrão. :-)
Orbling em
4
@Orbling eles são comumente usados ​​para falar sobre tais valores em JS.
Alnitak
+1 para descrever o operador corretamente, já que não é um operador lógico. Às vezes é chamado de "operador padrão".
Tim Büthe
@Tim A única diferença entre ||em JS (e Perl) e a versão em C, C ++ e Java é que JS não converte o resultado em um booleano. Ainda é um operador lógico.
Alnitak
@Alnitak: Possivelmente devido à formação não profissional de desenvolvedores JS no passado.
Orbling em
-1

Observe que em algumas versões do IE este código não funcionará conforme o esperado. Porque var, a variável é redefinida e atribuída de forma - se bem me lembro do problema - você acabará sempre tendo um novo objeto. Isso deve resolver o problema:

var AEROTWIST;
AEROTWIST = AEROTWIST || {};
ZER0
fonte