Verificação nula de JavaScript

170

Encontrei o seguinte código:

function test(data) {
    if (data != null && data !== undefined) {
        // some code here
    }
}

Sou um pouco novo em JavaScript, mas, a partir de outras perguntas que tenho lido aqui, tenho a impressão de que esse código não faz muito sentido.


Em particular, esta resposta afirma que

Você receberá um erro se acessar uma variável indefinida em qualquer contexto que não seja typeof.

Atualização: a (citação da) resposta acima pode ser enganosa. Deve dizer «uma variável não declarada» , em vez de «uma variável não definida» .

Como descobri, nas respostas de Ryan ♦ , maerics e nwellnhof , mesmo quando nenhum argumento é fornecido para uma função, suas variáveis ​​para os argumentos sempre são declaradas. Esse fato também prova errado o primeiro item da lista abaixo.


Pelo meu entendimento, os seguintes cenários podem ser observados:

  • A função foi chamada sem argumentos, criando assim datauma variável indefinida e gerando um erro data != null.

  • A função foi chamada especificamente com null(ou undefined), como argumento, caso em que data != nulljá protege o código interno, tornando-o && data !== undefinedinútil.

  • A função foi chamada com um argumento não nulo; nesse caso, passará trivialmente ambos data != null e data !== undefined .

P: Meu entendimento está correto?


Eu tentei o seguinte, no console do Firefox:

--
[15:31:31.057] false != null
[15:31:31.061] true
--
[15:31:37.985] false !== undefined
[15:31:37.989] true
--
[15:32:59.934] null != null
[15:32:59.937] false
--
[15:33:05.221] undefined != null
[15:33:05.225] false
--
[15:35:12.231] "" != null
[15:35:12.235] true
--
[15:35:19.214] "" !== undefined
[15:35:19.218] true

Não consigo descobrir um caso em que o data !== undefined depois data != null possa ser útil.

afsantos
fonte
9
Apenas use if (data). É uma maneira mnemônica de Javascript para verificar se a datavariável é avaliada como verdadeira. undefined, null, Falso, 0, cadeia vazia, matriz vazia e objecto (?) Sem propriedades avaliada como falsa, o resto é verdadeiro.
J0HN
20
@ J0HN - Usar if(data)significaria que ele não pode passar falseou 0como valores data.
Techfoobar
@ J0HN Além disso, a mesma resposta que mencione também afirma que:, if(typeof someUndefVar == whatever) -- workse if(someUnderVar) -- error.
afsantos 21/05
2
Provavelmente deveria ser data !== null && data !== undefined, o que é equivalente ao data != nullque é equivalente data != undefined. A forma anterior tende a ser favorecida, pois é mais explícita sobre as condições, ao passo que seria fácil ignorar essas duas nulle undefinedestá sendo verificada com as duas condições posteriores.
ZzzzBov
2
A propósito, testes explícitos para undefinedIMO são um cheiro de código. Não é uma palavra-chave protegida null, é uma variável indefinida. Isto é completamente válida e vai quebrar seu código:undefined = 1
Izkata

Respostas:

106

Uma "variável indefinida" é diferente do valor undefined.

Uma variável indefinida:

var a;
alert(b); // ReferenceError: b is not defined

Uma variável com o valor undefined:

var a;
alert(a); // Alerts “undefined”

Quando uma função usa um argumento, esse argumento é sempre declarado, mesmo que seu valor seja undefinede, portanto, não haverá nenhum erro. Você está certo sobre != nullseguido de !== undefinedser inútil, no entanto.

Ry-
fonte
32
data !== null && data !== undefinedfaria sentido, no entanto.
Bfavaretto
@bfavaretto: Sim, então pode ser um erro de digitação. Mas você nunca sabe ...: D
Ry-
1
Assim como eu pensei, obrigado pelo esclarecimento. Além disso, não acho que seja um erro de digitação. Eu executei uma busca e contagem em todo o script e ele encontrou 10 ocorrências, então ... acho que o autor também precisa de esclarecimentos sobre isso.
afsantos 21/05
2
Risque o meu comentário acima: na verdade, data != nullverificaria ambos nulle undefined(mas, curiosamente, apenas para nulle undefined, e não os outros valores falsos).
Bfavaretto 21/05
90

Em JavaScript, nullé um objeto singleton especial que é útil para sinalizar "sem valor". Você pode testá-lo por comparação e, como de costume no JavaScript, é uma boa prática usar o ===operador para evitar confusão de tipo de coerção:

var a = null;
alert(a === null); // true

Como @rynah menciona, "indefinido" é um pouco confuso em JavaScript. No entanto, é sempre seguro testar se a typeof(x)string é "indefinida", mesmo que "x" não seja uma variável declarada:

alert(typeof(x) === 'undefined'); // true

Além disso, as variáveis ​​podem ter o "valor indefinido" se não forem inicializadas:

var y;
alert(typeof(y) === 'undefined'); // true

Juntando tudo, seu cheque deve ficar assim:

if ((typeof(data) !== 'undefined') && (data !== null)) {
  // ...

No entanto, como a variável "data" é sempre definida, pois é um parâmetro de função formal, o uso do operador "typeof" é desnecessário e você pode comparar com segurança diretamente com o "valor indefinido".

function(data) {
  if ((data !== undefined) && (data !== null)) {
    // ...

Este trecho equivale a dizer "se a função foi chamada com um argumento definido e não é nulo ..."

maerics
fonte
5
Por que deveria parecer assim? != nullserá verdadeiro para todos os valores, exceto nulle undefined, e temos certeza de que essa variável é declarada. typeofem outras situações, pode até ser perigoso - e se você digitar incorretamente o nome da variável? Isso pode ser detectado por um longo tempo, porque não há erro.
Ry-
@maerics Então, se eu seguisse sua resposta corretamente, em uma verificação nula como no cenário acima, você não usaria !=nada, apenas uma comparação estrita !==?
afsantos
@rynah: Eu não presumo saber o suficiente sobre a solução geral do OP para saber se um teste nulo é apropriado ou não, mas eu editei para mencionar o fato de que usar "typeof" é desnecessário.
maerics
@afsantos: na realidade, não acho que muitos valores (algum?) serão convertidos para nulo; no entanto, é uma prática recomendada usar a comparação estrita ( ===), a menos que você realmente saiba o que está fazendo e queira comparar após a conversão ( ==).
Maerics
1
@ Izkata: Largue qualquer biblioteca que tente redefinir undefined. Além disso, o Safari no iPad fará isso em nenhuma circunstância. Você não pode nem delete window.undefined.
Ry-
10

No seu caso, use data==null(que é verdadeiro APENAS para nulo e indefinido - na segunda imagem, concentre-se em linhas / colunas nulo indefinido)

Aqui você tem todos ( src ):

E se

insira a descrição da imagem aqui

== (sua negação ! = )

insira a descrição da imagem aqui

=== (sua negação ! == )

insira a descrição da imagem aqui

Kamil Kiełczewski
fonte
8

P: A função foi chamada sem argumentos, tornando os dados uma variável indefinida e gerando um erro nos dados! = Null.

R: Sim, dataserá definido como indefinido. Consulte a seção 10.5 Instanciação de encadernação da declaração das especificações. Mas acessar um valor indefinido não gera um erro. Você provavelmente está confundindo isso com o acesso a uma variável não declarada no modo estrito, o que gera um erro.

P: A função foi chamada especificamente com null (ou indefinido), como argumento. Nesse caso, data! = Null já protege o código interno, tornando inútil && data! == indefinido.

P: A função foi chamada com um argumento não nulo; nesse caso, passará trivialmente os dados! = Null e data! == indefinidos.

A: correto. Observe que os seguintes testes são equivalentes:

data != null
data != undefined
data !== null && data !== undefined

Consulte a seção 11.9.3 O algoritmo de comparação de igualdade de igualdade e a seção 11.9.6 O algoritmo de comparação de igualdade estrita da especificação.

Nwellnhof
fonte
Eu não estava confundindo com variáveis ​​não declaradas, realmente não sabia como funcionava quando nenhum argumento foi fornecido. Eu estava convencido de que dataisso não existiria, em vez de ser definido undefined. Agradeço o esclarecimento, e essas referências me ajudaram a entender com mais detalhes como as duas igualdades funcionam.
afsantos 21/05
3

Eu acho que testar variáveis ​​para valores que você não espera não é uma boa ideia em geral. Porque o teste como você pode considerar como escrever uma lista negra de valores proibidos. Mas e se você esquecer de listar todos os valores proibidos? Alguém, até você, pode decifrar seu código transmitindo um valor inesperado. Portanto, uma abordagem mais apropriada é semelhante à lista de permissões - testando variáveis ​​apenas para os valores esperados, não inesperados. Por exemplo, se você espera que o valor dos dados seja uma sequência, em vez disso:

function (data) {
  if (data != null && data !== undefined) {
    // some code here
    // but what if data === false?
    // or data === '' - empty string?
  }
}

faça algo assim:

function (data) {
  if (typeof data === 'string' && data.length) {
    // consume string here, it is here for sure
    // cleaner, it is obvious what type you expect
    // safer, less error prone due to implicit coercion
  } 
}

fonte
2

typeof foo === "undefined"é diferente de foo === undefined, nunca os confunda. typeof foo === "undefined"é o que você realmente precisa. Além disso, use !==no lugar de!=

Portanto, a declaração pode ser escrita como

function (data) {
  if (typeof data !== "undefined" && data !== null) {
    // some code here
  }
}

Editar:

Você não pode usar foo === undefinedpara variáveis ​​não declaradas.

var t1;

if(typeof t1 === "undefined")
{
  alert("cp1");
}

if(t1 === undefined)
{
  alert("cp2");
}

if(typeof t2 === "undefined")
{
  alert("cp3");
}

if(t2 === undefined) // fails as t2 is never declared
{
  alert("cp4");
}

fonte
1
Ok, mas a variável é declarada neste caso, então qual é o problema?
Ry-
Pessoalmente, acho foo === undefinedperigoso usar. Isso faz com que seu código falhe na mesma condição que você estava tentando impedir.
Eu estou falando sobre o argumento para a função em questão. Veja também meu outro comentário .
Ry-
1
Por que isso está sendo rebaixado? A primeira frase é uma distinção correta e importante !
Izkata
1
@ Izkata: porque não há explicação para a afirmação inicial. foo === undefinedé perfeitamente aceitável na situação do OP (supondo undefinedque não tenha sido substituído). A resposta também falha em explicar por que !== deve ser usado no lugar de !=.
21313 Matt
1

A maneira simples de fazer seu teste é:

function (data) {
    if (data) { // check if null, undefined, empty ...
        // some code here
    }
}
Kadiri
fonte
5
Este teste não depende do contexto? Quero dizer, se o tipo esperado para datafor uma string, esse teste retornará false em strings vazias, o que pode ou não ser apropriado (a função pode querer lidar com a string vazia de alguma forma).
afsantos 21/05
5
Exceto que se "dados" tiver o valor ""ou 0ou NaN(ou outros), o bloco "se" será ignorado; que pode ou não ser a intenção do OP.
maerics
Desculpe @afsantos, eu não vi seu comentário, se você quiser se tornar falso quando os dados forem indefinidos, nulos ... exceto quando a data estiver vazia, será necessário criar outra var toTest = data; com um outro teste após o primeiro, como: if (toTest == "") {// algum código aqui}
Kadiri
-5
var a;
alert(a); //Value is undefined

var b = "Volvo"; 
alert(b); //Value is Volvo

var c = null;
alert(c); //Value is null
transbordar
fonte
4
Por favor, adicione alguma explicação sobre o que isso significa.
Ry-
Isto realmente não verificar para null.
user4642212