2011-01-18 18 views
199

El jQuery Core Style Guidelines sugiere dos formas diferentes de verificar si una variable está definida.variable === undefined vs. typeof variable === "undefined"

  • variables globales: typeof variable === "undefined"
  • variables locales: variable === undefined
  • Propiedades: object.prop === undefined

¿Por qué utiliza jQuery un enfoque para las variables globales y otro para los locales y propiedades?

+0

No puedo responder a la pregunta de por qué jQuery usaría ambos enfoques, pero JavaScript tiene algunas peculiaridades interesantes que significan estas dos cosas son sutilmente diferentes.No debería importar la mayor parte del tiempo (es decir, si su código es sensato), pero hay diferencias, sin embargo: consulte aquí para una reseña - http://wtfjs.com/2010/02/15/undefined-is- mutable – Spudley

+0

Como señaló @Struppi, la función más externa de jQuery tiene un argumento llamado indefinido. Dentro de jQuery, 'foo === undefined' se compara con la copia local de indefinido en lugar de global (window.undefined), que puede haber sido modificado por código demente. El hecho de que undefined sea mutable es definitivamente digno de mención y me alegra que lo hayas hecho. (+1) –

Respuesta

250

Para las variables no declaradas, typeof foo devolverá la cadena literal "undefined", mientras que el control de identidad foo === undefined desencadenaría el error "foo no está definido".

Para las variables locales (que usted sabe se declaran en algún lugar), no se produciría ningún error de este tipo, de ahí la comprobación de identidad.

+0

+1, había olvidado mencionar este punto. He actualizado mi respuesta para incluir esto, espero que no te importe. –

+1

@goreSplatter No puede eliminarlo ahora. :-) Fue difícil elegir, pero por la forma en que se formula la pregunta, esta respuesta es mejor. Cualquiera que esté interesado en cómo funciona indefinido en general (como yo) también debería mirar las otras respuestas, especialmente @ Tim's. –

+2

Agregaría comillas ('typeof foo; // ->" undefined "') para enfatizar que es una cadena y no el valor primitivo 'undefined'. – c24w

4

Porque undefined no siempre se declara, pero jQuery declara undefined en su función principal. Entonces usan el valor seguro undefined internamente, pero afuera usan el estilo typeof para estar seguros.

90

Me limitaría a usar typeof foo === "undefined" en todas partes. Eso nunca puede ir mal.

Imagino la razón por jQuery recomienda los dos métodos diferentes es que definen su propia undefined variable dentro de la función que el código jQuery vive en, por lo que dentro de esa función undefined está a salvo de la manipulación desde el exterior. También me imagino que alguien en algún lugar ha evaluado los dos enfoques diferentes y descubrió que foo === undefined es más rápido y por lo tanto decidió que es el camino a seguir. [ACTUALIZACIÓN: como se señala en los comentarios, la comparación con undefined también es un poco más corta, lo que podría ser una consideración.] Sin embargo, la ganancia en situaciones prácticas será absolutamente insignificante: este cheque nunca, nunca será ningún tipo de cuello de botella , y lo que pierde es significativo: evaluar una propiedad de un objeto host para su comparación puede arrojar un error, mientras que un control typeof nunca lo hará.

Por ejemplo, se usa la siguiente en IE para analizar XML:

var x = new ActiveXObject("Microsoft.XMLDOM"); 

Para comprobar si tiene un método loadXML con seguridad:

typeof x.loadXML === "undefined"; // Returns false 

Por otro lado:

x.loadXML === undefined; // Throws an error 

ACTUALIZACIÓN

Otra ventaja del cheque typeof que olvidé mencionar es que también funciona con variables no declaradas, lo que no ocurre con el cheque foo === undefined, y de hecho arroja un ReferenceError. Gracias a @LinusKleen por recordarme.Por ejemplo:

typeof someUndeclaredVariable; // "undefined" 
someUndeclaredVariable === undefined; // throws a ReferenceError 

Conclusión: utilice siempre el cheque typeof.

+6

Gracias Tim. Su punto sobre el rendimiento tiene sentido. El equipo de jQuery probablemente esté más preocupado por el impacto en el tamaño del archivo. 'foo === undefined', cuando se minimiza, es probablemente algo como' f === u', mientras que 'typeof foo === undefined" 'solo se puede reducir a' typeof f === "undefined" '. –

+1

Puede definir 'var u =" undefined "' y reducirlo a 'typeof f == u', lo que mejora pero aún es más grande. –

+2

Buenos puntos, pero no estoy seguro de la seguridad de 'typeof' contra las variables no declaradas es una ventaja. En todo caso, permite que los errores tipográficos pasen desapercibidos más fácilmente, y no puedo ver cuándo realmente querría verificar el tipo de variables no declaradas. –

22

Otra razón más para usar la variante typeof: undefined se puede redefinir.

undefined = "foo"; 
var variable = "foo"; 
if (variable === undefined) 
    console.log("eh, what?!"); 

El resultado de typeof variable no puede.

Actualización: tenga en cuenta que este no es el caso en ES5.

+10

Increíble punto, pero redefiniendo indefinido ... solo dañó mis ojos. –

+14

No se puede redefinir en ES5. – Ryan

+3

La propiedad global 'undefined' no se puede redefinir en ES5, pero aún se puede sombrear con una variable local. 'void 0' es más corto y seguro. – Oriol

-1

typeof a === 'undefined' es más rápido a continuación, a === 'undefined' por cerca de 2 veces en v6.9.1 nodo.

0

Para las variables locales, la comprobación con localVar === undefined funcionará porque deben haberse definido en algún lugar dentro del alcance local o no se considerarán locales.

para variables que no son locales y no se definen en cualquier lugar, el cheque someVar === undefined lanzará una excepción: ReferenceError no detectada: j no está definido

Aquí hay un código que permitirá aclarar lo que estoy diciendo anteriormente. Preste atención a los comentarios en línea para mayor claridad.

function f (x) { 
    if (x === undefined) console.log('x is undefined [x === undefined].'); 
    else console.log('x is not undefined [x === undefined.]'); 

    if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].'); 
    else console.log('x is not undefined [typeof(x) === \'undefined\'].'); 

    // This will throw exception because what the hell is j? It is nowhere to be found. 
    try 
    { 
     if (j === undefined) console.log('j is undefined [j === undefined].'); 
     else console.log('j is not undefined [j === undefined].'); 
    } 
    catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');} 

    // However this will not throw exception 
    if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.'); 
    else console.log('j is not undefined [typeof(x) === \'undefined\'].'); 
}; 

Si llamamos el código anterior como esto:

f(); 

La salida sería la siguiente:

x is undefined [x === undefined]. 
x is undefined [typeof(x) === 'undefined']. 
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code. 
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw. 

Si llamamos el código anterior como éstos (con cualquier valor en realidad) :

f(null); 
f(1); 

La salida serán los siguientes:

x is not undefined [x === undefined]. 
x is not undefined [typeof(x) === 'undefined']. 
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code. 
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw. 

Al hacer el registro de entrada como esta: typeof x === 'undefined', que está pidiendo esencialmente esto: Por favor, compruebe si la variable x existe (se ha definido) en alguna parte del código fuente. (más o menos). Si conoce C# o Java, este tipo de comprobación nunca se realiza porque, si no existe, no se compilará.

<== Fiddle Me ==>