Por que existe um valor `null` em JavaScript?

115

Em JavaScript, existem dois valores que basicamente dizem 'Não existo' - undefinede null.

Uma propriedade à qual um programador não atribuiu nada será undefined, mas para que uma propriedade se torne null, nulldeve ser explicitamente atribuída a ela.

Uma vez pensei que havia uma necessidade de nullporque undefinedé um valor primitivo e nullum objeto. Não é, mesmo que typeof nullvá render 'object': Na verdade, ambos são valores primitivos - o que significa nem undefinede nem nullpodem ser retornados de uma função de construtor, já que ambos serão convertidos em um objeto vazio (é necessário lançar um erro para proclamar a falha nos construtores).

Ambos também avaliam falseem contextos booleanos. A única diferença real em que consigo pensar é que um avalia para NaN, o outro para 0em contextos numéricos.

Então, por que há ambos undefinede nullse isso apenas confunde os programadores que estão verificando incorretamente nullao tentar descobrir se uma propriedade foi definida ou não?

O que eu gostaria de saber é se alguém tem um exemplo razoável onde é necessário usar e nullque não pode ser expresso usando undefined.

Portanto, o consenso geral parece ser que undefinedsignifica 'não existe tal propriedade', enquanto nullsignifica 'a propriedade existe, mas não tem valor'.

Eu poderia conviver com isso se as implementações de JavaScript realmente aplicassem esse comportamento - mas undefinedé um valor primitivo perfeitamente válido, portanto, pode ser facilmente atribuído a propriedades existentes para quebrar esse contrato. Portanto, se você quiser ter certeza de que existe uma propriedade, você deve usar a inoperadora ou hasOwnProperty()mesmo assim. Então, mais uma vez: qual é o uso prático para valores separados para undefinede null?

Na verdade, eu uso undefinedquando desejo cancelar a definição de valores de propriedades que não estão mais em uso, mas que não desejo delete. Devo usar em nullvez disso?

Christoph
fonte
3
Para responder à sua última pergunta: Não, você não deve definir propriedades como undefined.
Shog9 de
4
"undefined" é apenas uma variável no escopo global com o valor primitivo "undefined". É possível definir outro valor para a variável: {undefined = "Hello"; alert (undefined);} Uma maneira mais confiável de testar undefined: {if (typeof myvar === "undefined") alert ("undefined")}
cerca de
1
Consulte a seção 4.3.9-12 em ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf para undefined / null, e 15.1.1.3 para a variável "undefined" no escopo global.
cerca de
1
Você deve excluir um objeto ou defini-lo como nulo se isso fizer mais sentido, mas não como indefinido.
cerca de
4
In JavaScript, there are two values which basically say 'I don't exist' - undefined and null.Não, apenas undefineddiz isso.
Lightness Races in Orbit

Respostas:

78

A questão não é realmente "por que existe um valor nulo em JS" - existe um valor nulo de algum tipo na maioria das linguagens e geralmente é considerado muito útil.

A questão é: "por que existe um valor indefinido em JS". Principais lugares onde é usado:

  1. quando você declara, var x;mas não atribui a ele, xmantém undefined;
  2. quando sua função obtém menos argumentos do que declara;
  3. quando você acessa uma propriedade de objeto inexistente.

nullcertamente teria funcionado tão bem para (1) e (2) *. (3) deve realmente lançar uma exceção imediatamente, e o fato de que não faz, em vez de retornar este estranho undefinedque irá falhar mais tarde, é uma grande fonte de dificuldade de depuração.

*: você também pode argumentar que (2) deve lançar uma exceção, mas então você teria que fornecer um mecanismo melhor e mais explícito para argumentos padrão / variáveis.

No entanto, JavaScript originalmente não tinha exceções, ou qualquer forma de perguntar a um objeto se ele tinha um membro com um certo nome - a única maneira era (e às vezes ainda é) acessar o membro e ver o que você obtém. Dado que nulljá tinha um propósito e talvez você queira definir um membro para ele, um valor fora de banda diferente foi necessário. Então, nós temos undefined, é problemático como você apontou, e é outro grande 'recurso' de JavaScript do qual nunca seremos capazes de nos livrar.

Na verdade, uso undefined quando desejo cancelar a definição dos valores das propriedades que não estão mais em uso, mas que não desejo excluir. Devo usar null em vez disso?

Sim. Mantenha undefinedcomo um valor especial para sinalizar quando outras linguagens podem lançar uma exceção.

nullgeralmente é melhor, exceto em algumas interfaces DOM do IE, em que definir algo como nullpode gerar um erro. Freqüentemente, neste caso, a configuração para a string vazia tende a funcionar.

bobince
fonte
10
Args são expansíveis. Você pode inserir quantos quiser e uma função pode iterar e fazer uso de todos eles. Os objetos podem ser atribuídos a uma nova propriedade a qualquer momento. Ambos são recursos poderosos, mas suspeito que lançar exceções como você prefere causaria uma grande sobrecarga. IMO, vale a pena a troca. Eu gasto muito menos tempo verificando a existência em JS do que normalmente faço lançando em paradigmas de linguagem mais rígidos.
Erik Reppen
Engraçado como a resposta aceita para uma pergunta começa com "essa não é realmente a pergunta ..."
Phillip
@bobince as primeiras versões do JS não tinham o inoperador ou hasOwnProperty? Porque são muito mais seguros do que obj.hello !== undefinedpara verificar se existe uma propriedade em um objeto.
Andy
Esqueça, eu respondi minha própria pergunta. De acordo com o MDN, ambos foram introduzidos no ES3.
Andy
37

Melhor descrito aqui , mas em resumo:

undefined é a falta de um tipo e valor, e null é a falta de um valor.

Além disso, se você está fazendo comparações '==' simples, você está certo, elas são iguais. Mas tente ===, que compara o tipo e o valor, e você notará a diferença.

Eddie Parker
fonte
1
Eu sei disso null !== undefined- minha pergunta era por que havia a necessidade de duas coisas que expressam o mesmo conceito semântico; além disso, seu link menciona que 'null é um objeto' - isso está errado, é um primitivo ...
Christoph
2
Eles não são o mesmo conceito semântico. Para mim, pelo menos, há uma diferença significativa entre uma propriedade que recebe um valor nulo e uma propriedade que não existe.
Daniel Schaffer
Mas é só isso, eles não são o mesmo conceito semântico. O nulo é coagido ao usar == para implicar a mesma coisa, como uma conveniência para o programador.
Eddie Parker de
1
@EricElliott: typeofmentiras - leia as especificações ou tente retornar nullde um construtor
Christoph
5
@EricElliott: o valor de retorno dos construtores não tem nada a ver com falsidade, mas com a condição de objeto: se o valor de retorno é um objeto, retorne isso; se for um primitivo como nullou 42, descarte o valor de retorno e retorne o objeto recém-criado
Christoph,
17

Não acho que haja qualquer razão para ter ambos nulle undefined, porque o único motivo que muitas pessoas sugeriram (" undefinedsignifica que não existe essa variável / propriedade") não é válido, pelo menos em JavaScript. undefinednão pode dizer se a variável / propriedade existe ou não.

console.log(foo);               // "ReferenceError: foo is not defined"
                                // foo does not exist
var foo;
console.log(foo);               // "undefined", a different response
console.log(foo === undefined); // "true", but it does exist

var obj = {};
console.log(obj.hasOwnProperty("foo")); // "false", no such property
obj.foo = undefined;
console.log(obj.hasOwnProperty("foo")); // "true", it exists and has the value "undefined"
console.log(obj.foo === undefined);     // "true", but it does exist

obj.bar = "delete me";
obj.bar = undefined;
console.log(obj.hasOwnProperty("bar")); // "true", not actually deleted
delete obj.bar;
console.log(obj.hasOwnProperty("bar")); // "false", deleted

Como você pode ver, a verificação foo === undefinednão informa se fooexiste e a configuração obj.bar = undefinednão exclui realmente bar.

Pode ser a intenção original do autor do JavaScript que undefineddeve representar "não existência". No entanto, a implementação não foi assim.

Lei Zhao
fonte
1
Substitua undefinedpor nullem seus exemplos de código acima e as respostas serão todas iguais. Não tenho certeza de como isso responde à pergunta. Isso foi um comentário sobre a resposta de outra pessoa?
Eric Elliott
1
@EricElliott Minha resposta à pergunta é que não há razão para ter ambos nulle undefined, porque a única razão que muitas pessoas sugeriram não é válida.
Lei Zhao
Você deve editar sua resposta e realmente dizer isso. Eu poderia ter votado positivamente se você tivesse dado essa resposta. =)
Eric Elliott
@EricElliott Acho que você está certo. Eu editei minha resposta. Obrigado!
Lei Zhao
3
Na verdade, este exemplo mostra que, se você não atribuiu uma variável, ela retorna undefined. Mas se você atribuiu undefineda ele, não é realmente undefined- foi definido com undefinede tem referência a ele. A única diferença entre undefinede nullé seu uso e propósito histórico. Ambos são atômicos.
Aleksej Komarov
6

É perfeitamente possível precisar de ambos. Por exemplo, se você consultar o WMI, é inteiramente possível que uma classe retorne propriedades com um valor nulo. Eles são definidos, mas são nulos no momento.

EBGreen
fonte
6

Eu acho que sua conclusão de que JavaScript define undefinedcomo "não existe tal propriedade" enull como "a propriedade não tem valor" está perfeitamente correta. E em uma linguagem tão dinâmica como JavaScript é uma distinção muito importante. O uso da tipagem duck significa que precisamos ser capazes de diferenciar entre uma propriedade que não existe e não tem um valor. É nosso principal meio de derivar informações de tipo. em uma linguagem tipificada estaticamente, há uma distinção definida entre um campo ser nulo e um campo não existente. Em JavaScript, isso não é diferente. No entanto, é verificado em tempo de execução e pode ser modificado até esse momento.

Vou ter que concordar que a implementação é estranha, já que muitas vezes a distinção fica confusa. No entanto, acho que em JavaScript a distinção é importante. E ser capaz de atribuirundefined é essencial.

Lembro-me de ter lido uma postagem no blog há algum tempo sobre um RPG online escrito em JavaScript. Ele usou exemplos em que os objetos foram criados como cópias de instâncias existentes em vez de protótipos (classes, funções, qualquer coisa) e foram então alterados. Isso realmente me fez entender o quão poderoso isso undefinedpoderia ser ao modificar objetos existentes, mas não consigo lembrar quem o escreveu.

Jack ryan
fonte
Você poderia compartilhar este RPG?
Michael
3

Semanticamente, eles significam coisas diferentes. O tipo null possui exatamente um valor em seu domínio, null e uma propriedade pode ser atribuída a este valor específico. Indefinido representa uma falta distinta de qualquer valor atribuído.

AnthonyWJones
fonte
1
mas você pode usar undefinedmuito bem para atribuir propriedades, então este contrato (só devolver undfinedse não houver tal propriedade) pode ser facilmente quebrado pelo programador ...
Christoph
2
Você pode , mas definitivamente não deveria. Undefined é usado como uma forma muito básica / simplista de exceção em JavaScript - não o use como um valor e atribua-o a alguma propriedade! Isso é louco cara.
rfunduk
3

Como um programador Java, vejo uma grande diferença entre undefined e null. Codificando JavaScript, nem tanto, porque o JavaScript não é fortemente tipado e as diferenças entre undefined e null são borradas pelas conversões automáticas que são freqüentemente realizadas por tempo de execução. BTW, eu aproveito frequentemente essas conversões; eles tornam meu código JS mais compacto e legível.

Para responder à sua pergunta, indefinido significa que um valor nunca foi definido. Em termos práticos, isso geralmente aponta para um bug. Se yourObject.property for indefinido, isso significa que você não definiu a propriedade por algum motivo, ou estou procurando por algo que não existe. Este é um problema real ao trabalhar em um projeto com mais de um codificador.

null significa que "nenhum valor" foi definido explicitamente. Na prática, você está me dizendo algo sobre a propriedade, talvez que ela não seja usada neste contexto, ou que um valor ainda não tenha sido determinado.

Em Java, as tentativas de acessar um campo indefinido sempre resultarão em uma exceção. Na verdade, o compilador pode ser feito para avisá-lo sobre isso em seu código.

Steve11235
fonte
0

Experimente este exemplo:

<html>
<head>
    <script type="text/javascript">
        function ShowObjProperties(obj) {
            var property, propCollection = "";

            for(property in obj) {
                propCollection += (property + ": " + obj[property] + "\n");
            }

            alert(propCollection);
        }

        var obj = {
            userid: 3,
            name: 'me!',
            speak: function() { alert('Hi! My name is ' + this.name + ' and my ID is ' + this.userid + '.'); }
        }

        //Shows all properties
        ShowObjProperties(obj);

        //The Speak function is no longer in the list!
        delete obj.speak;
        alert(typeof obj.speak);
        ShowObjProperties(obj);

        //The UserID is still listed, it just has no value!
        obj.userid = null;
        ShowObjProperties(obj);
    </script>
</head>
<body>

</body>
</html>

Eu acho que há um uso muito real para 2 tipos diferentes aqui.

EndangeredMassa
fonte
E em protótipos, eu acho, um membro é nulo ou apenas indefinido.
Kev de
mas isso só funciona enquanto ninguém tentar quebrá-lo - se eu definir obj.userid = undefined, ele falhará - veja a última edição da minha pergunta
Christoph
0

Tudo se resume à natureza dinâmica dos javascripts.

As coisas podem ser indefinidas para que possam ser adicionadas posteriormente. É por isso que o javascript é tão poderoso e extensível.

Rob Stevenson-Leggett
fonte
e isso é relevante para a minha pergunta de que maneira?
Christoph de
2
É relevante porque responde à sua pergunta. 'null' é uma espécie de 'singleton' que significa 'não tem valor'. 'undefined' significa que algo é ... chocante, eu sei ... não definido. São coisas completamente diferentes.
rfunduk
0

é um recurso importante da linguagem se você envolver seu programa em torno do paradigma de eventos do javascript.

// a key exists as a placeholder for something
if(obj[name] === null) 
// no key exists int eh hashtable that is in this object
if(obj[name] === undefined)

isso é muito útil se você estiver lidando com um conjunto de dados que precisa de um valor para representar 'nada' para indicar alguma ação diferente de usar 'nada' para indicar a ação padrão.

filter_func_pt = {
  date:function(d){ return Math.round(d.getTime()/1000);},
  user: null,
}

function transform(obj){
    var ret = {};
    for( var prop in obj){
       var f = filter_func_pt[prop];
       if(f)
          ret[prop] = f(obj);
       else if(filter_func_pt[prop] === null)
         continue;
       else
         ret[prop] == obj;
    }
  return ret;
}

var a = {
   date: new Date(),
   user: 'sam'
   votes: [23, 41, 55] 
};

var b = transform(a);

/* b = {
 *    date: 1298582417
 *    votes: [23, 41, 55]
 * }
 */

no código acima a palavra-chave nula e o servidor indefinido propósitos muito claros e diferentes. a pesquisa que não é encontrada no objeto filter_func_pt que retorna meios indefinidos para adicionar a propriedade ao objeto de retorno como está, enquanto um valor nulo indica que o valor deve ser retido, e não adicionado, e a presença de qualquer valor verdadeiro neste case representa uma função usada para transformar o valor antes de adicioná-lo ao objeto ret .

Corvo de fogo
fonte
Este exemplo é artificial e um pouco sem sentido. Nulo não esclarece sua intenção de forma alguma - em vez disso, mascara-a. Você poderia ter usado uma string mais explícita para esclarecer o significado. Por exemplo, 'reter' ou 'retirar' e então você também poderia ser mais explícito sobre o tipo de função e realmente verificar a presença de uma função.
Eric Elliott
0

null é lindo

assim como todos os outros tipos de Live Script.

cite: No JavaScript, existem dois valores que basicamente dizem 'Eu não existo' - indefinido e nulo.

Por que você quer dizer coisas incorretas ?!

"null" é "Objeto vazio", assim como "0" é um "Número vazio" . 0, não é nada -ainda existe como um tipo de número. null é claro também está vazio, mas "é" e é uma coisa bem definida de um tipo de objeto .

É comum falar dessas coisas como "tipos", quando não são. Na verdade, eles são "categorias". Mas agora acabou.

Portanto, vou insistir e dizer que "nulo" é um tipo de objeto sem um tipo. E "null" diz "Eu existo muito [!], Mas não tenho conteúdo do meu tipo".

Considerando que undefined não possui o tipo e o tipo, onde undefined também é sua definição de tipo. Um tipo indefinido de um tipo torna-se sua tipologia distinta. Uma espécie de pergunta [o "nada" existe e como você define o "nada"?].

cite: undefined nem null podem ser retornados de uma função construtora, pois ambos serão conversores em um objeto vazio

Você conseguiu dizer uma coisa errada mais uma vez. Claro que não, o "indefinido" não é um Objeto, é um Sinal claro que nós humanos entendemos; mas ao contrário do que null está - e está lhe dizendo que: seu tipo está correto, mas o tipo que você está procurando não está contido nele, ou pelo menos - não neste momento. Venha nos visitar mais tarde, quando colocarmos \ designar algum objeto \ nele.

citar: A única diferença real que consigo pensar é que um avalia para NaN, o outro para 0 em contextos numéricos.

Isso mostra toda a sua distinção central, como mencionado: undefined é um token simples e, uma vez que é feito do mesmo material "genético" que seus parentes distantes: strings, a operação [+ undefined] irá convertê-lo em pato para NaN, similarmente nulo, é claro que se transforma em um tipo correto de 0 \ Número, e ao contrário de indefinido, isso se transforma em uma string (! Que não está vazia!) E é exatamente por isso que produz NaN . Onde: + undefined >> + "undefined" >> NaN. Já que o contexto numérico espera um valor explícito.

Enquanto o contexto booleano espera referência - não encontra nada para converter e produz 'falso'.

Vamos cortar agora ...

cite: Então, mais uma vez: qual é o uso prático para valores separados para undefined e null?

Vou tentar dar-lhe apenas dois exemplos empíricos e espero que seja suficiente

oElement.onclick >> null

// significa que a propriedade existe; seu valor esperado é Type: Object , e esse oElement suporta o evento "onclick"!

oElement.innerText >> ""

// significa - a propriedade existe; seu valor esperado é do tipo: String , o que significa que oElement oferece suporte à propriedade "innerText".

em ambos os casos - se você receber "undefined", significa que a propriedade não existe; não é compatível ou tem uma implementação incorreta (fornecedor ua).

Fique frio e divirta-se.

Bill the Lizard
fonte
Não vandalize suas postagens, aeneas. Exclua-os (usando o botão Excluir logo acima deste comentário) se quiser remover sua contribuição.
Michael Petrotta
não existe um botão de exclusão - mas caso você o veja, clique nele!
0

depois de ler uma discussão incrível sobre undefined vs null, uma pequena pesquisa no google me levou à documentação do Mozilla https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null é mencionado - null é frequentemente recuperado em um lugar onde um objeto pode ser esperado, mas nenhum objeto é relevante.

Não é semelhante ao padrão de objeto nulo https://en.wikipedia.org/wiki/Null_object_pattern

Então eu acho que faz sentido ter tipo de dados Nulo.

Documentação também mencionada como typeof null // "objeto" (não "null" por motivos legados)

Não tenho certeza de quais são os motivos legados

Vishal Bhandare
fonte