"Por conhecimento, entendo a certeza que nasce da comparação de ideias." ―David Hume

Neste artigo vamos ver quando usar o método hasOwnProperty, os operadores in, typeof, instanceof, e, de quebra, como utilizá-los para evitar comparações desnecessárias com null.

Null é um problema em todas as linguagens, pois sempre gera demanda por tratamento para que exceções não sejam lançadas. O próprio criador do null se refere a ele como um dos principais erros programação. De acordo com ele, foi um erro que causou prejuízo bilionário no setor:

"I call it my billion-dollar mistake. It was the invention of the null reference in 1965" - Tony Hoare

Alguns programadores são tão pragmáticos com o uso do null que simplesmente evitam ao máximo passá-lo como parâmetro ou retorná-lo na chamada de uma função. Normalmente, essa prática vem acompanhada de outra, chamada command query separation que estabelece que todos os métodos devem ter uma clara separação entre queries e commands. Queries são métodos que irão retornar um valor sem modificar nenhum estado, enquanto commands alteram o estado de um ou mais objetos, porém sem retornar nenhuma variável.

Enfim, null é problemático, o próprio criador dele admite. Sendo assim, qualquer prática que evite confusão com a referência nula, é uma prática boa.

typeof - Detectando Valores Primitivos e Funções.

O operador typeof trabalha em um variável e retorna uma string, indicando o tipo do valor.

  • Para strings, typeof retorna“string.”
  • Para numbers, typeof retorna“number.”
  • Para booleans, typeof retorna“boolean.”
  • Para undefined, typeof retorna“undefined.”

O operador typeof é excelente para reconhecimento de valores primitivos, como os acima citados. Para detecção de valores de referência, entretanto, eles não possuem serventia:

console.log(typeof {}); // "object"  
console.log(typeof []); // "object"  
console.log(typeof new Date()); // "object"  
console.log(typeof new RegExp()); // "object"  
console.log(typeof null); // "object"  

Veja que typeof não possibilita distinguir valores nulos, arrays nem objetos de classes diferentes. Dessa forma, fica bem claro que seu uso deve se restringir ao reconhecimento de valores primitivos.

Existe, porém, uma outra situação em que typeof deve ser utilizado e essa é para o reconhecimento de funções:

console.log(typeof document.getElementById); // "function"  

instanceof - Detectando Valores de Referência

O operador instanceof vem pra suprir a necessidade de se distinguir instâncias de classes diferentes. É preciso, porém, ficar alerta, pois ele realiza o reconhecimento de instâncias seguindo a cadeia de protótipos. Por conta disso, a variável "filho" no exemplo abaixo é considerada uma instância não somente de "Filho", mas também de "Pai" e "Object".

function Pai(sobrenome) {  
  this.sobrenome = sobrenome
}

function Filho(nome, idade) {  
  this.nome = nome;
  this.idade = idade;
}

Filho.prototype = new Pai("Carvalho");  
var filho = new Filho("Johel Jr", "2");

console.log(filho instanceof Object); // true  
console.log(filho instanceof Pai); // true  
console.log(filho instanceof Filho); // true  

isArray - Detectando Arrays

Arrays são objetos, então por que não simplesmente utilizar o operador instanceof para reconhecê-los?

console.log([] instanceof Array) // true  

Como você pode ver acima, é possível utilizar instanceof para reconhecer arrays, porém ele tem uma limitação: ele nem sempre funciona para detectar arrays provenientes de "frames" diferentes.

Diante disso, por um tempo o reconhecimento de array possuía um tratamento especial em aplicações até a chegada do ECMAScript 5 quando aconteceu a padronização da solução do problema. Com exceção de browsers antigos, todos implementam o método Array.isArray.

console.log(Array.isArray([])) // true  

Detectando propriedades

Tome como exemplo o objeto a seguir:

var profissional = {  
    profissao: "desenvolvedor",
    experiencia: 0
}

É uma prática comum entre programadores JavaScript utilizar o condicional a seguir. O problema aqui é que queremos detectar a existência das propriedades e não seus valores.

if(profissional.experiencia){  
    ...(alguma coisa)
}

O problema é que o objeto "profissional" possui a propriedade experiencia, mas não fará "alguma coisa" porque o valor é considerado como falso no condicional.

Outra maneira ineficaz é fazer comparações com null e undefined, posto que as propriedades podem propositalmente possuir esses valores, invalidando a detecção de propriedades.

// Ruim: Comparar com nulo
if (profissional[experiencia] != null) {  
  ...(alguma coisa)
}
// Ruim: Comparar com undefined
if (profissional[experiencia] != undefined) {  
  ...(alguma coisa)
}

A melhor prática para detecção de propriedades é utilizar o operador in e o método hasOwnProperty, conforme a seguir:

console.log("experiencia" in profissional) // true  
console.log(profissional.hasOwnProperty("experiencia")) // true  

A diferença entre os dois é que o operador in verifica a existência de uma propriedade em toda cadeia de protótipos, enquanto o método hasOwnProperty limita a busca nas propriedades que são diretamente do objeto.


Conclusão

Uma confusão que permeia a cabeça de quem está começando a programar em JavaScript é como decorar tantos "métodos" com nomes e objetivos aparentemente tão similares, como typeof, instanceof e hasOwnProperty. Em meio a essa confusão, acaba não sendo raro ver comparações com null e undefined. A regra básica é evitar esse tipo de comparação ao máximo, mas quando utilizá-la usar a igualdade tripla === para evitar maiores problemas.


Veja Também

Sobre o Autor

Johel Carvalho

Johel Carvalho

Engenheiro Civil formado pelo Instituto Militar de Engenharia (IME-RJ) em Dezembro de 2012. Largou a profissão pelo desenvolvimento web, começando com C# e sendo atualmente aficionado por JavaScript.

comments powered by Disqus