javascript define uma variável se indefinida

172

Eu sei que posso testar uma variável javascript e defini-la se for indefinida, mas não há como dizer

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

parece uma maneira muito mais clara e tenho certeza de que já vi isso em outros idiomas.

pedalpete
fonte
30
que é não um teste para "indefinido", é um teste para "Falsey"
Alnitak
3
Observe que isso localStorage.getItem()gerará uma exceção se o usuário tiver desativado os cookies (pelo menos no Chrome); portanto, convém try...catch
incluí-
1
Possível duplicata de O que a construção x = x || você quer dizer?
Michał Perłakowski

Respostas:

304

Sim, ele pode fazer isso, mas estritamente falando, isso atribuirá o valor padrão se o valor recuperado for falsey , ao contrário de verdadeiramente indefinido . Seria, portanto, não só igualar undefined, mas também null, false, 0, NaN, "" (mas não "0" ).

Se você deseja definir o padrão apenas se a variável for estritamente undefined, a maneira mais segura é escrever:

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

Em navegadores mais recentes, é realmente seguro escrever:

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

mas lembre-se de que é possível subvertê-lo em navegadores mais antigos, nos quais foi permitido declarar uma variável denominada undefinedcom um valor definido, causando falha no teste.

Alnitak
fonte
3
Estou surpreso que esse padrão não esteja incluído em mais bibliotecas JS.
Joemaller
existe uma desvantagem em usar var x = (x === undefined ? def_val : x);como um pouco mais longo var x = (typeof x === 'undefined') ? def_val : x;. O comportamento difere?
Marco Pashkov 25/02
3
Foi possível undefinedredefinir o @marco em navegadores antigos , causando falha no teste de igualdade.
Alnitak
@Alnitak, qual é a melhor abordagem para usar uma sintaxe semelhante à que o OP está usando e ainda verificar indefinidamente?
Ivo Pereira
@IvoPereira Você não pode usar a ||abordagem em um teste estrito para indefinido; você deve usar um teste explícito para undefinedcom um condicional.
Alnitak
26

A resposta do ES6 2018 é :

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

Se a variável x não estiver definida, retorne a variável y ... caso contrário, se a variável x estiver definida, retorne a variável x.

Sterling Bourne
fonte
4
Tanto quanto eu posso dizer, Object.isnão é melhor do que ===neste caso. "O operador === (e também o operador ==) trata os valores numéricos -0 e +0 como iguais e trata Number.NaN como diferente de NaN." ( developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/… ) Não importa aqui.
Trevor Dixon
5
Discordo. Conheça os dois e use o apropriado. Em particular, use Object.isse ambos os operandos estiverem NaN.
Trevor Dixon
2
Se Object.is () funciona em 100% dos casos de uso e === funciona em 98% dos casos de uso, por que você arriscaria usar ===? Por exemplo: console.log (+0 === -0); // gera true, enquanto console.log (Object.is (+0, -0)); // gera false - o que é melhor? 0 negativo é igual a 0 positivo? Essa é a pergunta que você deve se fazer, mas se você usar Object.is (), sempre saberá a resposta. Eles não são os mesmos, portanto, uma saída de false é o resultado correto e esperado.
Sterling Bourne
2
O contexto particular aqui está sempre se comparando a undefined. Então ===, funcionará 100% do tempo, não apenas 98%. A vantagem de ===ser mais fácil de ler, especialmente de relance, é mais curta e evita uma chamada de método desnecessária. Pessoalmente, eu usaria apenas Object.is()quando a situação exigir e preferir ===em todos os outros casos.
blubberdiblub
1
Absolutamente; se você é um programador experiente. A menos que você esqueça acidentalmente um sinal de igual, nesse caso, a depuração do porquê == não está funcionando em algum lugar é algo que eu nunca desejaria a qualquer desenvolvedor. Melhor prevenir do que remediar e sempre usar Object.is (), o motivo foi incluído na especificação especificamente para ajudar os desenvolvedores a escreverem menos códigos de bugs.
Sterling Bourne
7

Eu precisava "definir uma variável se indefinida" em vários lugares. Criei uma função usando a resposta @Alnitak. Espero que ajude alguém.

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

Uso:

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

Parece mais lógico verificar em typeofvez de undefined? Suponho que você espere um número ao definir o var 0quando indefinido:

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

Nesse caso, se getVariablenão for um número (string, objeto, qualquer que seja), setVariable será definido como0

Bruno
fonte
5

ES2020 Resposta

Com o Operador de coalizão nulo , você pode definir um valor padrão se valuefor nulo ou indefinido.

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

No entanto, você deve estar ciente de que o operador coalescente nulo não retorna o valor padrão para outros tipos de valor falso, como 0e ''.

Observe que o suporte do navegador para o operador é limitado. De acordo com os dados da caniuse , apenas 48,34% dos navegadores são suportados (a partir de abril de 2020). O suporte ao Node.js foi adicionado na versão 14 .

fui
fonte
2

Se você é um fã de FP ( programação funcional ), o Ramda possui uma função auxiliar pura para isso chamada defaultTo :

uso:

const result = defaultTo(30)(value)

É mais útil ao lidar com undefinedvalores booleanos:

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

Damian Green
fonte
1
isto é exatamente const result = value || 30;, exceto pelo uso de uma função intermediária e uma lib de +1000 bytes
Adelin
1
@ Adelin não é verdade, ele também lida com falsas para tipos booleanos. Se você já está usando esta biblioteca (como eu sou), é bastante útil e conciso #
Damian Green
1

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

Zikes
fonte
Também não atribuirá 0 se localStorage.getItem('value'))retornarfalse
Karl Adler
1

Também deparei com esse cenário hoje, onde eu não queria que zero fosse substituído por vários valores. Temos um arquivo com alguns métodos utilitários comuns para cenários como este. Aqui está o que eu adicionei para lidar com o cenário e ser flexível.

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;
    }
}

Em seguida, ele pode ser chamado com os dois últimos parâmetros sendo opcionais se eu desejar definir apenas valores indefinidos ou também substituir valores nulos ou 0. Aqui está um exemplo de uma chamada para ele que definirá o ID para -1 se o ID for indefinido ou nulo, mas não substituirá um valor 0.

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

Nos nossos dias, você realmente pode fazer sua abordagem com o JS:

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

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

console.log(x); // default value

Portanto, seu exemplo funcionará:

const setVariable = localStorage.getItem('value') || 0;
Tarkh
fonte
0

Funciona mesmo que o valor padrão seja um valor booleano:

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

Parece-me que, para implementações atuais de javascript,

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

é uma boa maneira de fazer isso (usando a desconstrução de objetos).

TS
fonte
0

Designação nula lógica, solução ES2020 +

Novos operadores estão sendo adicionados aos navegadores, ??=, ||=, e &&=. Esta postagem será focada ??=.

Isso verifica se o lado esquerdo está indefinido ou nulo, em curto-circuito, se já definido. Caso contrário, o lado direito é atribuído à variável do lado esquerdo.

Métodos de comparação

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

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

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

Exemplos 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

Exemplos 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" }

?? = Suporte do navegador julho de 2020 - 0,03%

?? = Documentação Mozilla

|| = Documentação Mozilla

&& = Documentação Mozilla

Gibolt
fonte
É realmente uma boa idéia copiar esta resposta para duas outras perguntas ( Substitua um valor se nulo ou indefinido em JavaScript e Existe um operador "coalescente nulo" em JavaScript? )? Não seria melhor VTC duplicar ou vincular perguntas relacionadas nos comentários?
user4642212 11/07
As perguntas são todas ligeiramente diferentes; como tal, são as respostas. Os exemplos são consistentes para melhorar rapidamente o contexto embutido. Provavelmente poderia ter se vinculado para obter mais detalhes, mas exigiria um salto extra que pode levar as pessoas a ignorar a solução
Gibolt