¿Qué significa “var FOO = FOO || {} ”(Asignar una variable o un objeto vacío a esa variable) ¿significa en Javascript?

99

Al mirar un código fuente en línea, encontré esto en la parte superior de varios archivos fuente.

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

Pero no tengo ni idea de lo que || {}hace.

Sé que {}es igual a new Object()y creo que ||es para algo como "si ya existe, use su valor, de lo contrario, use el nuevo objeto.

¿Por qué debería ver esto en la parte superior de un archivo fuente?

Ricardo Sánchez
fuente
Nota: La pregunta se editó para reflejar que este es un patrón de código que se ve comúnmente en la parte superior de los archivos fuente de JavaScript.
Robert Harvey

Respuestas:

153

Tu suposición en cuanto a la intención de || {}está bastante cerca.

Este patrón particular, cuando se ve en la parte superior de los archivos, se utiliza para crear un espacio de nombres , es decir, un objeto con nombre bajo el cual se pueden crear funciones y variables sin contaminar indebidamente el objeto global.

La razón por la que se usa es para que si tiene dos (o más) archivos:

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

y

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

ambos comparten el mismo espacio de nombres, entonces no importa en qué orden se carguen los dos archivos, todavía se obtiene func1y func2se define correctamente dentro del MY_NAMESPACEobjeto correctamente.

El primer archivo cargado creará el MY_NAMESPACEobjeto inicial y cualquier archivo cargado posteriormente aumentará el objeto.

De manera útil, esto también permite la carga asincrónica de scripts que comparten el mismo espacio de nombres, lo que puede mejorar los tiempos de carga de la página. Si las <script>etiquetas tienen el deferatributo establecido, no puede saber en qué orden se interpretarán, por lo que, como se describió anteriormente, esto también soluciona ese problema.

Alnitak
fuente
2
Este es exactamente el caso, hay un par de archivos js con exactamente la misma declaración al principio, ¡muchas gracias!
Ricardo Sanchez
41
+1 para leer entre líneas y explicar las razones para hacerlo. Siempre es bueno cuando alguien da la respuesta que el usuario realmente quería en lugar de solo la que pidió. :)
Spudley
1
Me gusta decir que es el # ifndef / # define para javascript :)
Darren Kopp
1
||también es realmente útil cuando desea proporcionar argumentos opcionales e inicializarlos a los valores predeterminados si no se proporcionan:function foo(arg1, optarg1, optarg2) { optarg1 = optarg1 || 'default value 1'; optarg2 = optart2 || 'defalt value 2';}
crazy2be
1
@ crazy2be que no funciona si el defecto es Truthy, pero los valores Falsey también son legales, ya que el ||operador no puede decir undefineda partir falsey.
Alnitak
23
var AEROTWIST = AEROTWIST || {};

Básicamente, esta línea dice establecer la AEROTWISTvariable en el valor de la AEROTWISTvariable, o establecerlo en un objeto vacío.

El conducto doble ||es una instrucción OR, y la segunda parte de OR solo se ejecuta si la primera parte devuelve falso.

Por lo tanto, si AEROTWISTya tiene un valor, se mantendrá como ese valor, pero si no se ha establecido antes, se establecerá como un objeto vacío.

es básicamente lo mismo que decir esto:

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

Espero que ayude.

Spudley
fuente
1
en realidad, el alcance estaría bien en su último ejemplo porque JS no tiene alcance de bloque
Alnitak
@Alnitak - meh, tienes razón; He estado trabajando demasiado con cierres últimamente y me he olvidado de los conceptos básicos. Editaré la respuesta.
Spudley
6

Otro uso común de || es establecer un valor predeterminado para un parámetro de función no definido también:

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

El equivalente en otra programación suele ser:

function display(a = 'default') {
  // ...
}
alessioalex
fuente
No es necesario varfrente a, amás entrar contexto de ejecución de la función como un parámetro formal , por lo que ya está declarada.
Fabrício Matté
6

Hay dos partes principales que var FOO = FOO || {};cubre.

# 1 Prevención de anulaciones

Imagine que tiene su código dividido en varios archivos y sus compañeros de trabajo también están trabajando en un objeto llamado FOO. Entonces podría dar lugar al caso de que alguien ya haya definido FOOy asignado una funcionalidad (como una skateboardfunción). Entonces lo anularía, si no estuviera comprobando si ya 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!');
};

En este caso, la skateboardfunción desaparecerá si carga el archivo JavaScript homer.jsdespués bart.jsen su HTML porque Homer define un nuevo FOOobjeto (y por lo tanto anula el existente de Bart), por lo que solo conoce la donutfunción.

Por lo tanto, debe usar lo var FOO = FOO || {};que significa "FOO se asignará a FOO (si ya existe) o un nuevo objeto en blanco (si FOO aún no existe).

Solución:

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

Debido a que Bart y Homer ahora están verificando la existencia de FOOantes de definir sus métodos, puede cargar bart.jsy homer.jsen cualquier orden sin anular los métodos del otro (si tienen nombres diferentes). Por lo tanto, siempre obtendrá un FOOobjeto que tenga los métodos skateboardy donut(¡Yay!).

# 2 Definiendo un nuevo objeto

Si ha leído el primer ejemplo, entonces ya sabe cuál es el propósito de || {}.

Porque si no hay un FOOobjeto existente, entonces el caso OR se activará y creará un nuevo objeto, por lo que puede asignarle funciones. Me gusta:

var FOO = {};

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

Si no hay valor en AEROTWIST o es nulo o indefinido, el valor asignado al nuevo AEROTWIST será {} (un objeto en blanco)

sudipto
fuente
1

El ||operador toma dos valores:

a || b

Si a es veraz , volverá a. De lo contrario, volverá b.

Los valores son Falsy null, undefined, 0, "", NaNy false. Los valores de verdad son todo lo demás.

Entonces, si ano se ha configurado (es undefined), regresará b.

pimvdb
fuente
No estoy seguro de que la verdad y la falsedad deban perpetuarse como palabras reales. Divertido, pero no exactamente estándar. :-)
Orbling
4
@Orbling se usan con bastante frecuencia para hablar sobre tales valores en JS.
Alnitak
+1 para describir correctamente al operador, ya que no es un operador lógico. A veces se le llama "operador predeterminado".
Tim Büthe
@Tim La única diferencia entre ||JS (y Perl) y la versión en C, C ++ y Java es que JS no convierte el resultado en un booleano. Sigue siendo un operador lógico.
Alnitak
@Alnitak: Posiblemente debido a la experiencia no profesional de los desarrolladores de JS en el pasado.
Orbling
-1

Tenga en cuenta que en alguna versión de IE este código no funcionará como se esperaba. Debido a que var, la variable se redefine y se asigna, por lo que, si recuerdo correctamente el problema, terminará teniendo siempre un objeto nuevo. Eso debería solucionar el problema:

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