Detectar una propiedad de objeto indefinida
¿Cómo verifico si la propiedad de un objeto en JavaScript no está definida?
La forma habitual de comprobar si el valor de una propiedad es el valor especial undefined
, es:
if(o.myProperty === undefined) {
alert("myProperty value is the special value `undefined`");
}
Para comprobar si un objeto no tiene realmente dicha propiedad y, por lo tanto, volverá undefined
de forma predeterminada cuando intente acceder a él:
if(!o.hasOwnProperty('myProperty')) {
alert("myProperty does not exist");
}
Para comprobar si el valor asociado a un identificador es el valor especial undefined
, o si ese identificador no ha sido declarado:
if(typeof myVariable === 'undefined') {
alert('myVariable is either the special value `undefined`, or it has not been declared');
}
Nota: este último método es la única forma de hacer referencia a un identificador no declarado sin un error temprano, lo cual es diferente a tener un valor de undefined
.
En versiones de JavaScript anteriores a ECMAScript 5, la propiedad denominada "indefinido" en el objeto global se podía escribir y, por lo tanto, una simple verificación foo === undefined
podría comportarse inesperadamente si se hubiera redefinido accidentalmente. En JavaScript moderno, la propiedad es de solo lectura.
Sin embargo, en JavaScript moderno, "indefinido" no es una palabra clave, por lo que las variables dentro de las funciones pueden denominarse "indefinido" y ocultar la propiedad global.
Si le preocupa este (improbable) caso límite, puede utilizar el operador void para obtener el undefined
valor especial en sí:
if(myVariable === void 0) {
alert("myVariable is the special value `undefined`");
}
Creo que hay varias respuestas incorrectas a este tema. Contrariamente a la creencia común, "indefinido" no es una palabra clave en JavaScript y, de hecho, se le puede asignar un valor.
Código correcto
La forma más sólida de realizar esta prueba es:
if (typeof myVar === "undefined")
Esto siempre devolverá el resultado correcto e incluso maneja la situación en la que myVar
no se declara.
Código degenerado. NO UTILICE.
var undefined = false; // Shockingly, this is completely legal!
if (myVar === undefined) {
alert("You have been misled. Run away!");
}
Además, myVar === undefined
generará un error en la situación en la que myVar no esté declarado.
Muchas respuestas aquí son vehementes en recomendar typeof
, pero typeof
es una mala elección . Nunca debe usarse para verificar si las variables tienen el valor undefined
, porque actúa como una verificación combinada del valor undefined
y de si existe una variable. En la gran mayoría de los casos, usted sabe cuándo existe una variable y typeof
solo introducirá la posibilidad de una falla silenciosa si comete un error tipográfico en el nombre de la variable o en el literal de cadena 'undefined'
.
var snapshot = …;
if (typeof snaposhot === 'undefined') {
// ^
// misspelled¹ – this will never run, but it won’t throw an error!
}
var foo = …;
if (typeof foo === 'undefned') {
// ^
// misspelled – this will never run, but it won’t throw an error!
}
Entonces, a menos que esté realizando una detección de características², donde existe incertidumbre sobre si un nombre determinado estará dentro del alcance (como verificar typeof module !== 'undefined'
como un paso en el código específico de un entorno CommonJS), typeof
es una opción dañina cuando se usa en una variable, y la opción correcta es para comparar el valor directamente:
var foo = …;
if (foo === undefined) {
⋮
}
Algunos conceptos erróneos comunes sobre esto incluyen:
que la lectura de una variable "no inicializada" (
var foo
) o parámetro (function bar(foo) { … }
, llamado comobar()
) fallará. Esto simplemente no es cierto: las variables sin inicialización explícita y los parámetros a los que no se les asignaron valores siempre se convierten enundefined
, y siempre están dentro del alcance.que
undefined
se puede sobrescribir. Es cierto queundefined
no es una palabra clave, pero es de sólo lectura y no configurable. Hay otras funciones integradas que probablemente no evites a pesar de que no son palabras clave (Object
,Math
,NaN
...) y el código práctico generalmente no está escrito en un entorno activamente malicioso, por lo que esta no es una buena razón para preocuparseundefined
. (Pero si estás escribiendo un generador de código, no dudes en utilizarlovoid 0
).
Una vez aclarado cómo funcionan las variables, es hora de abordar la pregunta real: las propiedades de los objetos. No hay ninguna razón para usarlo alguna vez typeof
para las propiedades del objeto. La excepción anterior con respecto a la detección de características no se aplica aquí; typeof
solo tiene un comportamiento especial en las variables y las expresiones que hacen referencia a las propiedades del objeto no son variables.
Este:
if (typeof foo.bar === 'undefined') {
⋮
}
siempre es exactamente equivalente a esto³:
if (foo.bar === undefined) {
⋮
}
y teniendo en cuenta los consejos anteriores, para evitar confundir a los lectores sobre por qué está usando typeof
, porque tiene más sentido usarlo ===
para verificar la igualdad, porque podría refactorizarse para verificar el valor de una variable más adelante y porque simplemente se ve mejor, siempre deberías usar === undefined
³ aquí también .
Otra cosa a considerar cuando se trata de propiedades de objetos es si realmente desea verificarlas undefined
. Un nombre de propiedad determinado puede estar ausente en un objeto (produciendo el valor undefined
cuando se lee), presente en el objeto mismo con el valor undefined
, presente en el prototipo del objeto con el valor undefined
, o presente en cualquiera de aquellos sin undefined
valor. 'key' in obj
le dirá si una clave está en algún lugar de la cadena prototipo de un objeto y Object.prototype.hasOwnProperty.call(obj, 'key')
le dirá si está directamente en el objeto. Sin embargo, no entraré en detalles en esta respuesta sobre prototipos y el uso de objetos como mapas con clave de cadena, porque su objetivo principal es contrarrestar todos los malos consejos en otras respuestas, independientemente de las posibles interpretaciones de la pregunta original. ¡ Lea sobre prototipos de objetos en MDN para obtener más información!
¹ ¿Elección inusual de nombre de variable de ejemplo? Este es un código muerto real de la extensión NoScript para Firefox.
Sin embargo, no asuma que no saber lo que está dentro del alcance está bien en general. Vulnerabilidad adicional causada por abuso del alcance dinámico: Proyecto Zero 1225
, asumiendo una vez más un entorno ES5+ y que undefined
se refiere a la undefined
propiedad del objeto global.
En JavaScript hay nulo y no definido . Tienen diferentes significados.
- indefinido significa que el valor de la variable no se ha definido; No se sabe cuál es el valor.
- nulo significa que el valor de la variable está definido y establecido en nulo (no tiene valor).
Marijn Haverbeke afirma, en su libro gratuito en línea " Eloquent JavaScript " (el énfasis es mío):
También existe un valor similar, nulo, cuyo significado es 'este valor está definido, pero no tiene valor'. La diferencia de significado entre indefinido y nulo es mayoritariamente académica y, por lo general, no es muy interesante. En los programas prácticos, a menudo es necesario comprobar si algo "tiene valor". En estos casos se puede utilizar la expresión algo == undefinido, porque, aunque no sean exactamente el mismo valor, null == undefinido producirá verdadero.
Entonces, supongo que la mejor manera de comprobar si algo no está definido sería:
if (something == undefined)
Las propiedades del objeto deberían funcionar de la misma manera.
var person = {
name: "John",
age: 28,
sex: "male"
};
alert(person.name); // "John"
alert(person.fakeVariable); // undefined
¿Qué significa esto: "propiedad de objeto indefinida" ?
¡En realidad puede significar dos cosas muy diferentes! Primero, puede significar la propiedad que nunca se ha definido en el objeto y, segundo, puede significar la propiedad que tiene un valor indefinido . Veamos este código:
var o = { a: undefined }
¿ Es o.a
indefinido? ¡Sí! Su valor no está definido. ¿ Es o.b
indefinido? ¡Seguro! ¡No existe ninguna propiedad 'b' en absoluto! Bien, veamos ahora cómo se comportan los diferentes enfoques en ambas situaciones:
typeof o.a == 'undefined' // true
typeof o.b == 'undefined' // true
o.a === undefined // true
o.b === undefined // true
'a' in o // true
'b' in o // false
Podemos ver claramente que typeof obj.prop == 'undefined'
y obj.prop === undefined
son equivalentes, y no distinguen esas diferentes situaciones. Y 'prop' in obj
puede detectar la situación cuando una propiedad no se ha definido en absoluto y no presta atención al valor de la propiedad que puede no estar definido.
¿Entonces lo que hay que hacer?
1) Quiere saber si una propiedad no está definida por el primer o segundo significado (la situación más típica).
obj.prop === undefined // IMHO, see "final fight" below
2) Solo desea saber si el objeto tiene alguna propiedad y no le importa su valor.
'prop' in obj
Notas:
- No se puede comprobar un objeto y su propiedad al mismo tiempo. Por ejemplo, esto
x.a === undefined
o estotypeof x.a == 'undefined'
aumentaReferenceError: x is not defined
si x no está definido. - La variable
undefined
es una variable global (por lo que en realidad lo eswindow.undefined
en los navegadores). Ha sido compatible desde ECMAScript 1.ª edición y desde ECMAScript 5 es de sólo lectura . Entonces, en los navegadores modernos no se puede redefinir como verdadero , como a muchos autores les encanta asustarnos, pero esto sigue siendo cierto para los navegadores más antiguos.
pelea final: obj.prop === undefined
vstypeof obj.prop == 'undefined'
Ventajas de obj.prop === undefined
:
- Es un poco más corto y se ve un poco más bonito.
- El motor JavaScript te dará un error si has escrito mal
undefined
Desventajas de obj.prop === undefined
:
undefined
se puede anular en navegadores antiguos
Ventajas de typeof obj.prop == 'undefined'
:
- ¡Es realmente universal! Funciona en navegadores nuevos y antiguos.
Desventajas de typeof obj.prop == 'undefined'
:
'undefned'
( mal escrito ) aquí es solo una constante de cadena, por lo que el motor de JavaScript no puede ayudarlo si lo ha escrito mal como lo acabo de hacer yo.
Actualización (para JavaScript del lado del servidor):
Node.js admite la variable global undefined
as global.undefined
(también se puede usar sin el prefijo 'global'). No conozco otras implementaciones de JavaScript del lado del servidor.
La cuestión se reduce a tres casos:
- El objeto tiene la propiedad y su valor no
undefined
. - El objeto tiene la propiedad y su valor es
undefined
. - El objeto no tiene la propiedad.
Esto nos dice algo que considero importante:
Existe una diferencia entre un miembro indefinido y un miembro definido con un valor indefinido.
Pero lamentablemente typeof obj.foo
no nos dice cuál de los tres casos tenemos. Sin embargo podemos combinar esto "foo" in obj
para distinguir los casos.
| typeof obj.x === 'undefined' | !("x" in obj)
1. { x:1 } | false | false
2. { x : (function(){})() } | true | false
3. {} | true | true
Vale la pena señalar que estas pruebas null
también son las mismas para las entradas.
| typeof obj.x === 'undefined' | !("x" in obj)
{ x:null } | false | false
Yo diría que en algunos casos tiene más sentido (y es más claro) verificar si la propiedad está ahí que verificar si no está definida, y el único caso en el que esta verificación será diferente es el caso 2, el raro caso de una entrada real en el objeto con un valor indefinido.
Por ejemplo: acabo de refactorizar un montón de código que tenía varias comprobaciones para determinar si un objeto tenía una propiedad determinada.
if( typeof blob.x != 'undefined' ) { fn(blob.x); }
Lo cual fue más claro cuando se escribió sin un cheque por indefinido.
if( "x" in blob ) { fn(blob.x); }
Pero como ya se ha mencionado, estos no son exactamente iguales (pero son más que suficientes para mis necesidades).