2012-06-05 811 views
15

Tome este fragmento,Indefinido, typeof indefinido, hasOwnProperty

var a = { 

} 

if(typeof a.c === 'undefined'){ 
console.log('inside if'); 
} 
if(a.c === undefined){ 
console.log('inside if'); 
} 

Ambos if resultados en true. ¿Hay alguna diferencia en ambas declaraciones específicas para algunos navegadores?

Además, en mi último proyecto ya he usado typeof a.c == 'undefined' numerosas veces para verificar los valores en json de datos.

Ahora, sé que esto no es bueno, ya que algunos valores también pueden ser undefined, por lo que mi lógica fallará.

Debería haber usado hasOwnProperty.

pero estoy seguro de que ningún valor será undefined, puedo utilizar typeof a.c == 'undefined' en lugar de hasOwnProperty o debería cambiar toda mi typeof con hasOwnProperty

+0

Sólo un comentario: aquí es como he visto hacer demasiado: https://github.com/olegskl/is.js/blob/master/is.js#L79 –

+0

Otra manera de hacerlo: 'si (ac === (function (u) {return u})()) {'... – Martijn

+1

Pregunta similar: http: // stackoverflow.com/preguntas/4725603/variable indefinido-vs-TypeOf-variable-indefinido – simon

Respuesta

21

(ACTUALIZACIÓN: Es posible que desee echa un vistazo a esta pregunta: variable === undefined vs. typeof variable === "undefined").

En muy viejos navegadores (Netscape 2, IIRC, y posiblemente IE 4 o inferior), no se puede comparar con un valor undefined, ya que provocó un error. En cualquier navegador (semi) moderno, sin embargo, no hay motivo para marcar typeof value === 'undefined' en lugar de value === undefined (excepto por la paranoia de que alguien haya redefinido la variable undefined).

hasOwnProperty tiene un propósito diferente. Comprueba si el objeto tiene una propiedad con el nombre de pila, y no su prototipo; es decir, independientemente de las propiedades heredadas. Si desea comprobar si un objeto contiene una cierta propiedad, heredado o no, se debe utilizar if ('c' in a) { ...

Pero básicamente, éstos probablemente todo el trabajo:

if (a.c === undefined) console.log('No c in a!'); 
if (typeof a.c === 'undefined') console.log('No c in a!'); 
if (!('c' in a)) console.log('No c in a!'); 
if (!a.hasOwnProperty('c')) console.log('No c in a!'); 

Las principales diferencias son que:

  • a.c === undefined producirá un resultado inesperado si alguien ha hecho undefined = 'defined' o algo por el truco;
  • !('c' in a) no es muy legible (en mi humilde opinión)
  • !a.hasOwnProperty('c') regresará false si el objeto a no contiene una propiedad c, pero su prototipo lo hace.

Personalmente, prefiero la primera ya que es más legible. Si usted es paranoico y quiere evitar el riesgo de un redefinido undefined, envuelva el código de una función anónima autoejecutable de la siguiente manera:

(function (undefined) { 
    // in here, 'undefined' is guaranteed to be undefined. :-) 

    var a = { 

    }; 

})(); 
+0

En la versión actual de Chrome, 'foo === undefined' desencadena un error. Ver esta respuesta: http://stackoverflow.com/a/4725697/851498 –

+0

Además, para la "paranoia", es por eso que mucha gente utiliza el siguiente truco: '(function (ventana, documento, no definido) {/ * código * /} (ventana, documento)); ':-) * Oh, que acaba de editar para añadir este * –

+1

@FlorianMargaine:. Ah, 'foo === undefined' es una buena. Sin embargo, es un argumento aún más convincente usar 'value === undefined', ya que le permite encontrar variables no declaradas, que son muy malas cosas ™. – Martijn

3

Si su comprobación de objetos estándar que son el resultado de analizar una cadena JSON , .hasOwnProperty no tiene ningún beneficio obvio. Excepto, por supuesto, si usted o alguna lib que está utilizando ha estado jugando con el Object.prototype.

En general, undefined como tal se puede redefinir, pero no he encontrado esto por mí mismo, ni creo que alguna vez lo haga. Sin embargo, es imposible (AFAIK) estropear los valores de retorno de typeof. En ese sentido, este último es la forma más segura de hacerlo. Creo que algunos navegadores antiguos tampoco funcionan bien con la palabra clave undefined.

Al reanudar: no hay necesidad de ir y reemplazar cada cheque typeof solo. En una nota personal: creo que es una buena práctica tener el hábito de usar .hasOwnProperty, sin embargo. Por lo tanto, sugeriría que, en caso de que exista una propiedad, pero no esté definida, .hasOwnPorperty es la apuesta más segura.


En respuesta a tu comentario: sí, typeof se ajuste a sus necesidades ~ 95% de las veces. .hasOwnProperty funcionará el 99% de las veces. Sin embargo, como su nombre indica: propiedades más arriba en la cadena de herencia no se compruebe, considere el siguiente ejemplo:

Child.prototype = new Parent(); 
Child.prototype.constructor=Child;//otherwise instance.constructor points to parent 

function Parent() 
{ 
    this.foo = 'bar'; 
} 

function Child() 
{ 
    this.bar = 'baz'; 
} 

var kiddo = new Child(); 
if (kiddo.hasOwnProperty('foo')) 
{ 
    console.log('This code won\'t be executed'); 
} 
if (typeof kiddo.foo !== 'undefined') 
{ 
    console.log('This will, foo is a property of Parent'); 
} 

Así que si usted quiere comprobar si un objeto tiene una propiedad, hasOwnProperty es lo que necesita . Especialmente si va a cambiar el valor de esa propiedad (si se trata de una propiedad prototipo, todas las instancias se pueden modificar).
Si desea saber si una propiedad tiene un valor (distinto de undefined), independientemente de dónde se encuentre en la cadena de herencia, necesitará typeof. Tengo una función recursiva en alguna parte para determinar dónde se puede encontrar la propiedad en la cadena de herencia. Una vez que lo encuentre, lo publicaré aquí también.

Actualización:

Como prometió, la función de localizar una propiedad en una cadena de herencia. No es la función real que utilicé hace un tiempo, así que armé un borrador en funcionamiento. No es perfecto, pero bien podría ayudarle en su camino:

function locateProperty(obj,prop,recursion) 
{ 
    recursion = recursion || false; 
    var current = obj.constructor.toString().match(/function\s+(.+?)\s*\(/m)[1]; 
    if (!(obj.hasOwnProperty(prop))) 
    { 
     if (current === 'Function' || recursion === current) 
     { 
      return false; 
     } 
     return locateProperty(new window[current](),prop,current); 
    } 
    return current; 
} 
//using the object kiddo 
locateProperty(kiddo,'foo');//returns 'Parent' 
locateProperty(kiddo,'bar');//returns 'Parent', too 

Para evitar este último problema técnico, se puede reemplazar la última declaración con return current;return obj;. O, mejor aún, agregue la línea siguiente al fragmento anterior:

Child.prototype.constructor=Child; 

me olvidaron que en la primera edición ...

+0

Entonces, no debería cambiar mi código, pero para el futuro, debería usar 'hasOwnProperty'. Correcto ? – Jashwant

+0

Editado mi respuesta, para proporcionar más información con respecto a su comentario. –

0
  • Copiar las propiedades enumerables de P a O, y devolver o .

  • Si o y p tienen una propiedad con el mismo nombre, la propiedad o se deja en paz.

  • Esta función no maneja getters y setters ni atributos de copia.

    function merge(o, p) 
    { 
        for(prop in p) 
        { 
         // For all props in p. 
         if (o.hasOwnProperty[prop]) continue; // Except those already in o. 
         o[prop] = p[prop];      // Add the property to o. 
        } 
    
        return o; 
    } 
    

¿Cuál es la diferencia entre o.hasOwnProperty[prop] y o.hasOwnProperty(prop)?