if (clave en objeto) o if (object.hasOwnProperty (clave)

173

¿Las siguientes dos declaraciones producen el mismo resultado? ¿Hay alguna razón para preferir un camino al otro?

 if (key in object)

 if (object.hasOwnProperty(key))
Lorena Bernard
fuente

Respuestas:

181

Tenga cuidado, no producirán el mismo resultado.

intambién regresará truesi keyse encuentra en algún lugar de la cadena del prototipo , mientras que Object.hasOwnProperty(como el nombre ya nos dice), solo regresará truesi keyestá disponible en ese objeto directamente (es "dueño" de la propiedad).

Andre Meinhold
fuente
3
¿A qué te refieres exactamente in will also return true if key gets found somewhere in the prototype chain? puedes escribir un ejemplo? Gracias.
Lorraine Bernard el
44
@Lor: ({foo:"bar"}).hasOwnProperty("toString")vs"toString" in ({foo:"bar"})
Odio a los perezosos el
68

Trataré de explicar con otro ejemplo. Digamos que tenemos el siguiente objeto con dos propiedades:

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

Creemos una instancia de TestObj:

var o = new TestObj();

Examinemos la instancia del 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

Conclusión:

  • en operador devuelve verdadero siempre, si el objeto puede acceder a la propiedad, directamente o desde el prototipo

  • hasOwnProperty () devuelve verdadero solo si la propiedad existe en la instancia, pero no en su prototipo

Si queremos verificar que exista alguna propiedad en el prototipo, lógicamente, 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:

Entonces, con respecto a la declaración de que estas dos condiciones ...

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

... produce el mismo resultado, la respuesta es obvia, depende.

Dalibor
fuente
28

intambién verificará las propiedades heredadas, lo cual no es el caso hasOwnProperty.

xavier.seignard
fuente
25

En resumen, hasOwnProperty()no se ve en el prototipo mientras inse ve en el prototipo.

Tomado de O'Reilly High Performance Javascript :

Puede determinar si un objeto tiene un miembro de instancia con un nombre dado usando el método hasOwnProperty () y pasando el nombre del miembro. Para determinar si un objeto tiene acceso a una propiedad con un nombre de pila, puede usar el operador in. Por ejemplo:

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

En este código, hasOwnProperty () devuelve verdadero cuando se pasa "título" porque el título es una instancia de objeto; el método devuelve falso cuando se pasa "toString" porque no existe en la instancia. Cuando se usa cada nombre de propiedad con el operador in, el resultado es verdadero las dos veces porque busca la instancia y el prototipo.

Etienne Noël
fuente
5

Tienes algunas respuestas realmente geniales. Solo quiero ofrecer algo que le ahorrará la necesidad de marcar "hasOwnProperty" mientras itera un objeto.

Al crear un objeto, generalmente las personas lo crearán de esta manera:

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

Ahora, si desea iterar a través de "someMap", deberá hacerlo de esta manera:

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

Lo estamos haciendo para evitar iterar sobre propiedades heredadas.

Si tiene la intención de crear un objeto simple que solo se utilizará como un "mapa" (es decir, pares clave-valor), puede hacerlo así:

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

Así que ahora será seguro iterar así:

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

Aprendí este increíble consejo aquí

asafel
fuente
1
una descripción
darcher
2

La otra forma (solicitada en) enumera los nombres de propiedad (o claves) de un objeto. En cada iteración, se asigna otra cadena de nombre de propiedad del objeto a la variable. Por lo general, es necesario probar object.hasOwnProperty (variable) para determinar si el nombre de la propiedad es realmente un miembro del objeto o si se encontró en su lugar en la cadena del prototipo.

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

(del Javascript de Crockford : las partes buenas )

Jahan
fuente
55
El inoperador es diferente a la for-indeclaración.
Odio a los perezosos el
En realidad, ambos son usos diferentes de la palabra clave
Jahan
44
Sí, ines una palabra clave. Pero OP pregunta sobre el uso específico como inoperador. Su respuesta trata con el otro uso como parte de la for-indeclaración.
Odio a los perezosos el
-3

La primera versión es más corta (especialmente en código minificado donde las variables cambian de nombre)

a in b

vs

b.hasOwnProperty(a)

De todos modos, como dijo @AndreMeinhold, no siempre producen el mismo resultado.

antonjs
fuente
1
Hubiera sido mejor tener esto como comentario. :-)
Hlawuleka MAS