if (chave no objeto) ou if (object.hasOwnProperty (chave)

173

As duas instruções a seguir produzem a mesma saída? Existe alguma razão para preferir um caminho para o outro?

 if (key in object)

 if (object.hasOwnProperty(key))
Lorraine Bernard
fonte

Respostas:

181

Tenha cuidado - eles não produzirão o mesmo resultado.

intambém retornará truese keyfor encontrado em algum lugar da cadeia de protótipos , enquanto que Object.hasOwnProperty(como o nome já nos diz), retornará apenas truese keyestiver disponível diretamente nesse objeto (seu "possui" a propriedade).

Andre Meinhold
fonte
3
para que exatamente você quer dizer in will also return true if key gets found somewhere in the prototype chain? você pode escrever um exemplo? obrigado.
Lorraine Bernard
44
@Lor: ({foo:"bar"}).hasOwnProperty("toString")vs"toString" in ({foo:"bar"})
Eu odeio o Lazy '
68

Vou tentar explicar com outro exemplo. Digamos que temos o seguinte objeto com duas propriedades:

function TestObj(){
    this.name = 'Dragon';
}
TestObj.prototype.gender = 'male';

Vamos criar uma instância do TestObj:

var o = new TestObj();

Vamos examinar a instância do objeto:

console.log(o.hasOwnProperty('name')); // true
console.log('name' in o); // true

console.log(o.hasOwnProperty('gender')); // false
console.log('gender' in o); // true

Conclusão:

  • O operador in retorna true sempre, se a propriedade estiver acessível pelo objeto, diretamente ou a partir do protótipo

  • hasOwnProperty () retorna true somente se a propriedade existir na instância, mas não em seu protótipo

Se quisermos verificar se existe alguma propriedade no protótipo, logicamente, diríamos:

console.log(('name' in o) && !o.hasOwnProperty('name')); //false
console.log(('gender' in o) && !o.hasOwnProperty('gender')); //true - it's in prototype

Finalmente:

Então, com relação à afirmação de que essas duas condições ...

if (key in object)
if (object.hasOwnProperty(key))

... produz o mesmo resultado, a resposta é óbvia, depende.

Dalibor
fonte
28

intambém verificará propriedades herdadas, o que não é o caso hasOwnProperty.

xavier.seignard
fonte
25

Em resumo, hasOwnProperty()não procura no protótipo enquanto inprocura no protótipo.

Retirado do O'Reilly High Performance Javascript :

Você pode determinar se um objeto tem um membro da instância com um nome especificado usando o método hasOwnProperty () e passando o nome do membro. Para determinar se um objeto tem acesso a uma propriedade com um determinado nome, você pode usar o operador in. Por exemplo:

var book = {
    title: "High Performance JavaScript",
    publisher: "Yahoo! Press" 
};

alert(book.hasOwnProperty("title"));  //true
alert(book.hasOwnProperty("toString"));  //false
alert("title" in book); //true 
alert("toString" in book); //true

Nesse código, hasOwnProperty () retorna true quando "title" é passado porque title é uma instância de objeto; o método retorna false quando "toString" é passado porque não existe na instância. Quando cada nome de propriedade é usado com o operador in, o resultado é verdadeiro duas vezes, porque pesquisa a instância e o protótipo.

Etienne Noël
fonte
5

Você tem ótimas respostas. Eu só quero oferecer algo que poupe a necessidade de verificar "hasOwnProperty" enquanto itera um objeto.

Ao criar um objeto, geralmente as pessoas o criam desta maneira:

const someMap = {}
// equivalent to: Object.create(Object.prototype)
// someMap.constructor will yield -> function Object() { [native code] }

Agora, se você quiser percorrer "someMap", precisará fazer o seguinte:

const key
for(key in someMap ){
 if (someMap.hasOwnProperty(key)) { 
   // Do something
 }
}

Estamos fazendo isso para evitar a iteração sobre propriedades herdadas.

Se você pretende criar um objeto simples que será usado apenas como um "mapa" (ou seja, pares de chave-valor), faça o seguinte:

const newMap = Object.create(null);
// Now, newMap won't have prototype at all.
// newMap.constructor will yield -> undefined

Portanto, agora será seguro iterar assim:

for(key in cleanMap){
 console.log(key + " -> " + newMap [key]);
 // No need to add extra checks, as the object will always be clean
}

Eu aprendi essa dica incrível aqui

asafel
fonte
1
um write-up mais detalhada: ryanmorr.com/true-hash-maps-in-javascript
darcher
2

O outro formulário (chamado in) enumera os nomes (ou chaves) de propriedades de um objeto. Em cada iteração, outra string de nome de propriedade do objeto é atribuída à variável. Geralmente é necessário testar object.hasOwnProperty (variável) para determinar se o nome da propriedade é realmente um membro do objeto ou foi encontrado na cadeia de protótipos.

 for (myvar in obj) {
     if (obj.hasOwnProperty(myvar)) { ... } }

(do Javascript de Crockford : The Good Parts )

Jahan
fonte
5
O inoperador é diferente da for-indeclaração.
Eu Odeio preguiçoso
Na verdade, os dois são usos diferentes da palavra
Jahan
4
Sim, iné uma palavra-chave. Mas o OP está perguntando sobre o uso específico como inoperador. Sua resposta lida com o outro uso como parte da for-indeclaração.
Eu Odeio preguiçoso
-3

A primeira versão é mais curta (especialmente no código minificado, onde as variáveis ​​são renomeadas)

a in b

vs

b.hasOwnProperty(a)

De qualquer forma, como o @AndreMeinhold disse, eles nem sempre produzem o mesmo resultado.

antonjs
fonte
1
Teria sido melhor ter isso como um comentário. :-)
Hlawuleka MAS