JavaScript establece una variable si no está definida

172

Sé que puedo probar una variable de JavaScript y luego definirla si no está definida, pero ¿no hay alguna forma de decirlo?

var setVariable = localStorage.getItem ('valor') || 0;

Parece una forma mucho más clara, y estoy bastante seguro de que he visto esto en otros idiomas.

pedalpete
fuente
30
eso no es una prueba para "indefinido", es una prueba para "falsey"
Alnitak
3
Tenga en cuenta que localStorage.getItem()arrojará una excepción si el usuario ha deshabilitado las cookies (al menos en Chrome), por lo que es posible que desee envolverlo dentro de una try...catchcláusula
finalice
1
Posible duplicado de ¿Qué significa la construcción x = x || y quieres decir?
Michał Perłakowski

Respuestas:

304

Sí, puede hacer eso, pero estrictamente hablando, asignará el valor predeterminado si el valor recuperado es falsey , en lugar de verdaderamente indefinido . Sería, por tanto, no sólo igualar undefined, sino también null, false, 0, NaN, "" (pero no "0" ).

Si desea establecer el valor predeterminado solo si la variable es estrictamente, undefinedentonces la forma más segura es escribir:

var x = (typeof x === 'undefined') ? your_default_value : x;

En los navegadores más nuevos, en realidad es seguro escribir:

var x = (x === undefined) ? your_default_value : x;

pero tenga en cuenta que es posible subvertir esto en navegadores antiguos donde se le permitió declarar una variable llamada undefinedque tiene un valor definido, lo que hace que la prueba falle.

Alnitak
fuente
3
Me sorprende que este patrón no esté incluido en más bibliotecas JS.
joemaller
¿Hay una desventaja de usar var x = (x === undefined ? def_val : x);como un poco más largo var x = (typeof x === 'undefined') ? def_val : x;? ¿El comportamiento difiere?
Marco Pashkov
3
@marco en navegadores más antiguos se pudo undefinedredefinir, lo que provocó que la prueba de igualdad fallara.
Alnitak
@Alnitak, ¿cuál es el mejor enfoque para usar una sintaxis similar a la que está usando OP y aún verificar si no está definida?
Ivo Pereira
@IvoPereira No puede usar el ||enfoque en una prueba estricta para indefinido, debe usar una prueba explícita para undefinedcondicional.
Alnitak
26

La respuesta ES6 2018 es :

return Object.is(x, undefined) ? y : x;

Si la variable x no está definida, devuelva la variable y ... de lo contrario, si la variable x está definida, devuelva la variable x.

Sterling Bourne
fuente
44
Por lo que puedo decir, Object.isno es mejor que ===en este caso. "El operador === (y el operador == también) trata los valores numéricos -0 y +0 como iguales y trata Number.NaN como no igual a NaN". ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ) No importa aquí.
Trevor Dixon
55
Estoy en desacuerdo. Conócelos a ambos y usa el apropiado. En particular, use Object.issi ambos operandos pueden ser NaN.
Trevor Dixon
2
Si Object.is () funciona en el 100% de los casos de uso, y === funciona en el 98% de los casos de uso, ¿por qué se arriesgaría a usar ===? Por ejemplo: console.log (+0 === -0); // genera true, mientras que console.log (Object.is (+0, -0)); // da como resultado falso, ¿cuál es mejor? ¿Es 0 negativo lo mismo que 0 positivo? Esa es la pregunta que debes hacerte, pero si usas Object.is (), siempre sabes la respuesta. No son lo mismo, por lo que una salida de falso es el resultado correcto y esperado.
Sterling Bourne
2
El contexto particular aquí siempre se compara undefined. Así ===funcionará el 100% del tiempo, no solo el 98%. La ventaja de ===ser más fácil de leer, especialmente de un vistazo, es más corta y evita una llamada de método innecesaria. Personalmente solo lo usaría Object.is()cuando la situación lo requiera y prefiera=== en todos los demás casos.
blubberdiblub
1
Absolutamente; Si eres un codificador experimentado. A menos que olvide accidentalmente un signo igual, en cuyo caso la depuración por la que == no funciona en algún lugar es algo que nunca desearía para ningún desarrollador. Es mejor prevenir que curar y usar siempre Object.is (). La razón por la que se incluyó en la especificación fue específicamente para ayudar a los desarrolladores a escribir menos código defectuoso.
Sterling Bourne
7

Necesitaba "establecer una variable si no estaba definida" en varios lugares. Creé una función usando la respuesta @Alnitak. Esperemos que ayude a alguien.

function setDefaultVal(value, defaultValue){
   return (value === undefined) ? defaultValue : value;
}  

Uso:

hasPoints = setDefaultVal(this.hasPoints, true);
Mcestone
fuente
6

Parece más lógico verificar en typeoflugar de undefined? Supongo que espera un número cuando establece la var 0cuando no está definido:

var getVariable = localStorage.getItem('value');
var setVariable = (typeof getVariable == 'number') ? getVariable : 0;

En este caso, si getVariableno es un número (cadena, objeto, lo que sea), setVariable se establece en0

Bruno
fuente
5

Respuesta de ES2020

Con el Operador de fusión nula , puede establecer un valor predeterminado si valuees nulo o no está definido.

const setVariable = localStorage.getItem('value') ?? 0;

Sin embargo, debe tener en cuenta que el operador de fusión nulo no devuelve el valor predeterminado para otros tipos de valores falsos como 0y ''.

Tenga en cuenta que el soporte del navegador para el operador es limitado. Según los datos de caniuse , solo el 48.34% de los navegadores son compatibles (a partir de abril de 2020). El soporte de Node.js se agregó en la versión 14 .

wentjun
fuente
2

Si eres un fan de FP ( programación funcional ), Ramda tiene una función de ayuda ordenada para esto llamada defaultTo :

uso:

const result = defaultTo(30)(value)

Es más útil cuando se trata de undefinedvalores booleanos:

const result2 = defaultTo(false)(dashboard.someValue)

Damian Green
fuente
1
esto es exactamente const result = value || 30;, excepto que está usando una función intermedia y +1000 bytes lib
Adelin
1
@Adelin no es cierto, también maneja falsedades para tipos booleanos. Si ya está usando esta biblioteca (como yo), entonces es bastante útil, y claro
Damian Green
1

var setVariable = (typeof localStorage.getItem('value') !== 'undefined' && localStorage.getItem('value')) || 0;

Zikes
fuente
No asignará también 0 si localStorage.getItem('value'))regresafalse
Karl Adler
1

Hoy también me encontré con este escenario donde no quería que se sobrescribiera cero para varios valores. Tenemos un archivo con algunos métodos de utilidad comunes para escenarios como este. Esto es lo que agregué para manejar el escenario y ser flexible.

function getIfNotSet(value, newValue, overwriteNull, overwriteZero) {
    if (typeof (value) === 'undefined') {
        return newValue;
    } else if (value === null && overwriteNull === true) {
        return newValue;
    } else if (value === 0 && overwriteZero === true) {
        return newValue;
    } else {
        return value;
    }
}

Luego se puede invocar con los dos últimos parámetros como opcionales si solo quiero establecer valores indefinidos o también sobrescribir valores nulos o 0. Aquí hay un ejemplo de una llamada que establecerá la ID en -1 si la ID no está definida o es nula, pero no sobrescribirá un valor 0.

data.ID = Util.getIfNotSet(data.ID, -1, true);
Mark Seefeldt
fuente
1

En nuestros días puedes hacer tu acercamiento con JS:

// Your variable is null
// or '', 0, false, undefined
let x = null;

// Set default value
x = x || 'default value';

console.log(x); // default value

Entonces su ejemplo FUNCIONARÁ:

const setVariable = localStorage.getItem('value') || 0;
tarkh
fuente
0

Funciona incluso si el valor predeterminado es un valor booleano:

var setVariable = ( (b = 0) => b )( localStorage.getItem('value') );
Tsz Lam Yau
fuente
0

Me parece que, para las implementaciones actuales de JavaScript,

var [result='default']=[possiblyUndefinedValue]

es una buena manera de hacer esto (usando la deconstrucción de objetos).

TS
fuente
0

Asignación nula lógica, solución ES2020 +

Los nuevos operadores se están agregando actualmente a los navegadores, ??=, ||=, y &&=. Esta publicación se centrará en??= .

Esto verifica si el lado izquierdo no está definido o es nulo, cortocircuitando si ya está definido. Si no, el lado derecho se asigna a la variable del lado izquierdo.

Métodos comparativos

// Using ??=
name ??= "Dave"

// Previously, ES2020
name = name ?? "Dave"

// Before that (not equivalent, but commonly used)
name = name || "Dave" // name ||= "Dave"

Ejemplos básicos

let a          // undefined
let b = null
let c = false

a ??= true  // true
b ??= true  // true
c ??= true  // false

// Equivalent to
a = a ?? true

Ejemplos de objeto / matriz

let x = ["foo"]
let y = { foo: "fizz" }

x[0] ??= "bar"  // "foo"
x[1] ??= "bar"  // "bar"

y.foo ??= "buzz"  // "fizz"
y.bar ??= "buzz"  // "buzz"

x  // Array [ "foo", "bar" ]
y  // Object { foo: "fizz", bar: "buzz" }

?? = Soporte del navegador Julio 2020 - .03%

?? = Documentación de Mozilla

|| = Documentación de Mozilla

&& = Documentación de Mozilla

Gibolt
fuente
¿Es realmente una buena idea copiar esta respuesta a otras dos preguntas ( Reemplace un valor si es nulo o indefinido en JavaScript y ¿Hay un operador de "fusión nula" en JavaScript? )? ¿No sería mejor VTC como duplicado o enlace a preguntas relacionadas en los comentarios?
user4642212
Las preguntas son todas ligeramente diferentes; Como tal, también lo son las respuestas. Los ejemplos son consistentes para mejorar el contexto en línea de un vistazo. Probablemente podría haberse vinculado para obtener más detalles, pero habría requerido un salto adicional que podría hacer que las personas omitan la solución
Gibolt