Qual é a razão para usar nulo em vez de indefinido em JavaScript?

103

Tenho escrito JavaScript há bastante tempo e nunca tive um motivo para usá-lo null. Parece que undefinedé sempre preferível e tem o mesmo propósito de maneira programática. Quais são algumas razões práticas para usar em nullvez de undefined?

Jimmy Cuadra
fonte
Esta é uma possível duplicata de stackoverflow.com/questions/461966/…
lawnsea
Bem, existem métodos como document.getElementById()esse que podem retornar, nullmas não undefined, então, nesses casos, por que você testaria o retorno undefined? (Claro, funcionaria se você usasse em ==vez de ===, mas ainda assim, por que você testaria deliberadamente para ver se há algo errado?)
nnnnnn
Pode ser útil ter tipos previsíveis e isso pode orientar o pensamento de usar um ou outro. Onde um objeto é sempre retornado, necessário ou desejado pelo design, use null para resultados falsos (por exemplo document.getElementById('does-not-exist')). As variáveis var a;e os valores de retorno da função são predefinidos como indefinidos. No passado, nulo estava no escopo global, portanto, usá-lo tornava a execução mais lenta e me fazia preferir outros tipos falsos (falso, '', 0) às referências livres. Eu pessoalmente evito null a menos que haja uma razão convincente de outra forma, porque eu o considero mais simples, o que geralmente é melhor.
jimmont

Respostas:

59

Nulo e indefinido são essencialmente dois valores diferentes que significam a mesma coisa. A única diferença está nas convenções de como você os usa em seu sistema. Como alguns mencionaram, algumas pessoas usam null para significar "nenhum objeto", onde às vezes você pode obter um objeto, enquanto indefinido significa que nenhum objeto era esperado (ou que houve um erro). Meu problema com isso é completamente arbitrário e totalmente desnecessário.

Dito isso, há uma grande diferença - variáveis ​​que não são inicializadas (incluindo parâmetros de função onde nenhum argumento foi passado, entre outras coisas) são sempre indefinidas.

É por isso que em meu código nunca uso nulo, a menos que algo que não controle retorne nulo (correspondência de regex, por exemplo). A beleza disso é que simplifica muito as coisas. Nunca preciso verificar se x === indefinido || x === null. E se você tem o hábito de usar == ou simplesmente coisas como if (x) .... Pare com isso. !xserá avaliado como verdadeiro para uma string vazia, 0, nulo, NaN - ou seja, coisas que você provavelmente não deseja. Se você quiser escrever javascript que não seja horrível, sempre use triplo igual a === e nunca use nulo (use undefined ao invés). Isso tornará sua vida muito mais fácil.

BT
fonte
137
Eu discordo disso. Nulo é usado para definir algo vazio de forma programática. Indefinido quer dizer que a referência não existe. Um valor nulo tem uma referência definida para "nada". Se você estiver chamando uma propriedade não existente de um objeto, será indefinido. Se eu quiser deixar essa propriedade intencionalmente vazia, ela deve ser nula para que você saiba que é propositalmente. Muitas bibliotecas javascript funcionam assim.
com2ghz
6
@ com2ghz O que você descreve é ​​uma de muitas filosofias. Muitas bibliotecas js realmente funcionam dessa maneira. Muitos também não funcionam assim. Em javascript, você pode armazenar facilmente um valor indefinido explícito em um objeto ou array, assim como em null. Os significados de ambos são completa e inteiramente dependentes do contexto. Ou seja, eles significam o que você quer que eles significem.
BT de
3
É por isso que JS é uma linguagem horrível. Como você disse, muitas bibliotecas têm suas próprias filosofias, mas você inclui muitas bibliotecas para 1 projeto. Portanto, você se depara com muitas convenções dessas bibliotecas. Quantas vezes você precisa fazer diferentes verificações falsas. Não seria a última vez que você concataria um objeto nulo em uma string e obteria um "nulo" como string. Ou passando 0 como valor numérico e perguntando-se por que a instrução IF trata é t como falso.
com2ghz
2
@ com2ghz Então JS é uma linguagem horrível porque tem nulo e indefinido? Eu posso contar dezenas de decisões de linguagem incorreta em todas as principais línguas, js não é exceção. Eu literalmente nunca preciso ou quero usar verificações falsas em meu código e sempre uso ===ou !==. JS é uma linguagem fantasticamente expressiva se você souber como usá-la.
BT
6
Certo. Acabei de saber que a dicotomia null/ undefinedera necessária porque a versão inicial do JS não tinha hasOwnPropertynem o inoperador. Agora que sim, eu realmente não entendo por que um deles não foi abolido no ES6 ou em qualquer proposta do ES7 que eu vi.
Andy
86

Eu realmente não tenho uma resposta, mas de acordo com Nicholas C. Zakas , página 30 de seu livro " Professional JavaScript for Web Developers " :

Ao definir uma variável que deve conter posteriormente um objeto, é aconselhável inicializar a variável nullcomo ao invés de qualquer outra coisa. Dessa forma, você pode verificar explicitamente o valor nullpara determinar se a variável foi preenchida com uma referência de objeto posteriormente

bbg
fonte
8
+1 sim, eu concordo e sempre tento lembrar de inicializar vars como nulo. Então tenho (bastante) certeza de que isso undefinedsignifica que aconteceu um desastre. Apenas imho.
Pete Wilson
9
@Pete - mas não diz nada sobre o "desastre", então qual é o ponto? E você só pode fazer essa suposição se souber que a função segue a convenção.
RobG
7
Por outro lado, você também pode inicializar a variável com var myVar;e verificar explicitamente o valor undefinedpara determinar se ele foi preenchido com uma referência de objeto posteriormente. Meu ponto é que isso é totalmente acadêmico - você pode fazer isso de qualquer maneira, e qualquer um que aconselhe de uma forma em vez de outra está simplesmente empurrando sua própria convenção.
thdoan
1
O único problema que tenho (desde que comecei com o JavaScript, 15 anos atrás) é que muitas vezes você precisa testar undefinede null. Isso ainda é muito chato. Evito atribuir uma variável a nullapenas para reduzir o número de nulltestes extras .
G Man
4
@GMan - Este é o único lugar onde a ==comparação (ao contrário de ===) faz sentido: v == null(ou v == undefined) verificará se há nulo ou indefinido.
Rick Love
14

No final do dia, porque nulle undefinedcoage ao mesmo valor ( Boolean(undefined) === false && Boolean(null) === false), você pode tecnicamente usar qualquer um para fazer o trabalho. No entanto, existe o caminho certo, IMO.

  1. Deixe o uso de undefinedpara o compilador JavaScript.

    undefinedé usado para descrever variáveis ​​que não apontam para uma referência. É algo que o compilador JS cuidará para você. No momento da compilação, o mecanismo JS definirá o valor de todas as variáveis ​​içadas como undefined. Conforme o mecanismo avança pelo código e os valores se tornam disponíveis, o mecanismo atribuirá os respectivos valores às respectivas variáveis. Para aquelas variáveis ​​para as quais não encontrou valores, as variáveis ​​continuariam a manter uma referência à primitiva undefined.

  2. Use nulo apenas se desejar denotar explicitamente o valor de uma variável como tendo "nenhum valor".

    Como @ com2gz afirma: nullé usado para definir algo vazio de forma programática. undefinedpretende dizer que a referência não existe. Um nullvalor tem uma referência definida para "nada". Se você estiver chamando uma propriedade não existente de um objeto, você obterá undefined. Se eu deixasse essa propriedade intencionalmente vazia, então deve ser nullpara que você saiba que é de propósito.

TLDR; Não use o undefinedprimitivo. É um valor que o compilador JS definirá automaticamente para você quando você declarar variáveis ​​sem atribuição ou se tentar acessar propriedades de objetos para os quais não há referência. Por outro lado, use nullse e somente se você deseja intencionalmente que uma variável "não tenha valor".

Eu nunca defini nada explicitamente como indefinido (e não encontrei isso nas muitas bases de código com as quais interagi). Além disso, raramente uso null. As únicas vezes que uso nullé quando quero denotar o valor de um argumento para uma função como sem valor, ou seja ,:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Govind Rai
fonte
Esta deveria ter sido a resposta selecionada
alaboudi,
13

indefinido é onde nenhuma noção da coisa existe; ele não tem tipo e nunca foi referenciado antes nesse escopo; null é onde se sabe que a coisa existe, mas não tem valor.

Yaplex
fonte
4
Como saber se foi feita uma tentativa de atribuir um valor, mas ela falhou e undefined foi atribuído?
RobG de
11

Todo mundo tem sua própria maneira de codificar e sua semântica interna, mas com o passar dos anos descobri que esse é o conselho mais intuitivo que dou às pessoas que fazem esta pergunta: na dúvida, faça o que o JavaScript faz .

Digamos que você esteja trabalhando com propriedades de objeto como opções para um plugin jQuery ... pergunte-se qual valor o JavaScript dá a uma propriedade que ainda não foi definida - a resposta é undefined. Portanto, neste contexto, eu inicializaria esses tipos de coisas com 'indefinido' para serem consistentes com JavaScript (para variáveis, você pode fazer em var myVar;vez de var myVar = undefined;).

Agora, digamos que você esteja fazendo manipulação de DOM ... que valor o JavaScript atribui a elementos inexistentes? A resposta é null. Este é o valor com o qual eu inicializaria se você estivesse criando uma variável de espaço reservado que posteriormente conterá uma referência a um elemento, fragmento de documento ou similar relacionado ao DOM.

Se você estiver trabalhando com JSON, um caso especial precisa ser feito: para valores de propriedade indefinidos, você deve configurá-los como ""ou nullporque um valor de undefinednão é considerado o formato JSON adequado.

Com isso dito, como um postador anterior expressou, se você descobrir que está inicializando coisas com nullou undefinedmais de uma vez na lua azul, então talvez você deva reconsiderar como você fará para codificar seu aplicativo.

thdoan
fonte
Embora esta seja uma boa posição, gostaria de adicionar esta resposta: stackoverflow.com/a/37980662/883303
Frederik Krautwald
@FrederikKrautwald, obrigado pelo link - esse é um delineamento muito claro.
thdoan
10

Você pode adotar a convenção sugerida aqui, mas realmente não há um bom motivo para isso. Não é usado de forma consistente o suficiente para ser significativo.

Para tornar a convenção útil, primeiro você deve saber que a função chamada segue a convenção. Em seguida, você deve testar explicitamente o valor retornado e decidir o que fazer. Se você obtiver indefinido , pode assumir que ocorreu algum tipo de erro conhecido pela função chamada . Mas se um erro aconteceu, e a função sabia disso, e é útil enviar isso para um ambiente mais amplo, por que não usar um objeto de erro? ou seja, lançar um erro?

Portanto, no final do dia, a convenção é praticamente inútil em qualquer coisa além de programas muito pequenos em ambientes simples.

RobG
fonte
3

Uma propriedade útil em null que undefined não se qualifica:

> null + 3
3
> undefined + 3
NaN

Eu uso nullquando quero 'desligar' um valor numérico ou inicializar algum. Meu último uso foi manipular a transformação css:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Não tenho certeza se devo usar este pensamento de propriedade ...

Faccion
fonte
2

Os nós e elementos DOM não são indefinidos, mas podem ser nulos.

  • O nextSibling do último filho de um elemento é nulo.

  • O irmão anterior do primeiro filho é nulo.

  • Uma referência document.getElementById será nula se o elemento não existir no documento.

Mas em nenhum desses casos o valor é indefinido ; simplesmente não há nenhum nó ali.

kennebec
fonte
Obrigada pelo esclarecimento. Para mim, isso não poderia ser mais contra-intuitivo.
tomekwi
Realmente depende do que você está tentando verificar. Por exemplo, se você quiser ver se uma variável global chamada 'myVar' existe, então window.myVarretornaria 'undefined se ela não existir. Existem toneladas de coisas que retornam 'indefinido' em JavaScript, apenas há toneladas de coisas que retornam 'nulo' - tudo depende do contexto.
thdoan
2

Alguns disseram que não há problema em inicializar objetos para null. Eu só queria apontar que os padrões de argumento de desestruturação não funcionam null. Por exemplo:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Isso requer a realização de nullverificações antes de chamar a função, o que pode acontecer com frequência.

Matt Way
fonte
1

Estou trabalhando exatamente nessa questão agora e observando a seguinte filosofia:

  1. Qualquer função que se destina a retornar um resultado deve retornar nulo se não conseguir encontrar um resultado
  2. Qualquer função que NÃO se destina a retornar um resultado retorna implicitamente indefinido.

Para mim, essa questão é significativa porque qualquer pessoa que chamar uma função que retorna um resultado não deve ter dúvidas sobre se deve testar indefinido versus nulo.

Esta resposta não tenta abordar:

  1. Valores de propriedade de nulo vs indefinido
  2. Variáveis ​​dentro de suas funções sendo nulas vs indefinidas

Na minha opinião, as variáveis ​​são da sua própria conta e não uma parte da sua API, e as propriedades em qualquer sistema OO são definidas e, portanto, devem ser definidas com valor diferente do que seriam se não fossem definidas (nulo para definido, indefinido é o que você obter ao acessar algo que não está em seu objeto).

Michael
fonte
1

Este é um motivo: var undefined = 1 é javascript legal, mas var null = 1é um erro de sintaxe. A diferença é que nullé uma palavra-chave do idioma, enquantoundefined , por algum motivo, não é.

Se seu código se baseia em comparações undefinedcomo se fosse uma palavra-chave ( if (foo == undefined)- um erro muito fácil de cometer), isso só funciona porque ninguém definiu uma variável com esse nome. Todo aquele código é vulnerável a alguém acidentalmente ou maliciosamente definir uma variável global com aquele nome. Claro, todos nós sabemos que definir acidentalmente uma variável global é totalmente impossível em javascript ...

Joel Mueller
fonte
1
Use em void 0vez de indefinido.
Frederik Krautwald,
1

Só quero acrescentar que com o uso de certas bibliotecas javascript, null e undefined podem ter consequências indesejadas.

Por exemplo, a getfunção de lodash , que aceita um valor padrão como terceiro argumento:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Outro exemplo: se você usar defaultProps no React, se uma propriedade for passada null, os props padrão não serão usados ​​porque null é interpretado como um valor definido . por exemplo

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
lilbitofchee
fonte
0

Discordo totalmente que o uso nulo ou indefinido seja desnecessário. indefinido é a coisa que mantém vivo todo o processo de encadeamento do protótipo. Portanto, o compilador apenas com nulo não pode verificar se esta propriedade é igual a nula ou não está definida no protótipo de terminal. Em outras linguagens de tipo dinâmico (por exemplo, Python), ele lança uma exceção se você deseja acessar uma propriedade não definida, mas para linguagens baseadas em protótipo, o compilador também deve verificar os protótipos pais e aqui são os locais quando os indefinidos mais precisam.

Todo o significado de usar nulo é apenas vincular variável ou propriedade com objeto que é único e tem significado de vazio, e também uso de nulo para fins de desempenho. Este 2 código tem tempo de execução diferente.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
VahagnNikoghosian
fonte
0

Variável desconhecida: undefined.

Variável conhecida ainda nenhum valor: null.

  1. Você recebe um objeto de um servidor server_object,.
  2. Você faz referência server_object.errj. Diz a você que é undefined. Isso significa que não sabe o que é.
  3. Agora você faz referência server_object.err. Diz a você que é null. Isso significa que você está referenciando uma variável correta, mas ela está vazia; portanto, nenhum erro.

O problema é quando você declara o nome de uma variável sem um valor ( var hello) js declara que como undefined: esta variável não existe; enquanto os programadores geralmente querem dizer: “Eu não dei um valor ainda”, a definição de null.

Portanto, o comportamento padrão de um programador - declarar uma variável sem valor como nada - está em desacordo com js - declarando-a como não existente. Além disso, !undefinede !nullsão ambos true, a maioria dos programadores os trata como equivalentes.

Você pode, é claro, garantir que sempre o faça, var hello = nullmas a maioria não vai bagunçar seu código como tal para garantir a sanidade de tipo em uma linguagem deliberadamente fracamente tipada, quando eles e o !operador tratam ambos undefinede nullcomo equivalentes.

newfivefour
fonte