2012-03-08 12 views
7

Por lo general me encuentro trabajando con objetos profundos como este:¿Cómo evitar el error "la propiedad de indefinido" sin tener una enorme instrucción if en JavaScript?

var x = { 
    y: { 
    z: { 
     a:true 
    } 
    } 
} 

y en algún lugar en el código:

if(x.y.z.a === true){ 
    //do something 
} 

Y en algunos casos ninguna de las x, y, las variables z podría ser indefinido, en cuyo caso se podrían obtener "no se puede leer la propiedad * de indefinido" solución

potencial es:

if(x && x.y && x.y.z && x.y.z.a === true){ 
    //do something 
} 

jsFiddle: http://jsfiddle.net/EcFLk/2/

Pero ¿hay alguna manera más fácil/más corto? Las soluciones en línea (sin usar funciones especiales) serían geniales. Gracias.

+0

El último es el más corto. Para nombres más largos, también puede usar: 'var tmp = x; if (tmp && (tmp = tmp.verylongname) && (tmp = tmp.evenlongernameblabla) && (tmp = tmp.doyougetit)) {...} '. –

+0

Me gustaría utilizar una función especial en este caso. –

+0

@Jesse, ¿puedes dar el ejemplo? – Sherzod

Respuesta

9

No, ya has encontrado el camino correcto. Por supuesto, puede usar un bloque try/catch y manejar el error después de los hechos, pero yo usaría la solución x && x.y && x.y.z && x.y.z.a.

(No es necesario el === true a menos que realmente desea la condición sólo es cierto cuando a es estrictamente igual a true y no cuando es 1 o "hi", pero a partir de su pregunta, estoy pensando en eso ya lo sabes .)


usted ha dicho que no desea utilizar una función para esto, y no he sentido la necesidad de uno cualquiera, sino sólo para ajustes y risitas:

function ref(obj, names) { 
    var rv = obj, index; 
    if (names) { 
     for (index = 0; rv && index < names.length; ++index) { 
      rv = rv[names[index]]; 
     } 
    } 
    return rv; 
} 

Uso:

if (ref(x, ["y", "z", "a"]) === true) { 
    // do something 
} 

llamadas a funciones son so cheap these days ...

O alternativamente:

function ref(obj) { 
    var rv = obj, index; 
    for (index = 1; rv && index < arguments.length; ++index) { 
     rv = rv[arguments[index]]; 
    } 
    return rv; 
} 

Uso:

if (ref(x, "y", "z", "a") === true) { 
    // do something 
} 

... pero en la mayoría de los motores de JavaScript, que será más lento (arguments tiende a ser lento). Pero, una vez más, tendrías que hacerlo miles de veces seguidas para que la velocidad sea un problema.

O como sugiere Šime, una sola variable (que estaba evitando la split, pero no es caro):

function ref(obj, path) { 
    var rv = obj, names = path.split("."), index; 
    for (index = 0; rv && index < names.length; ++index) { 
     rv = rv[names[index]]; 
    } 
    return rv; 
} 

Uso:

if (ref(x, "y.z.a") === true) { 
    // do something 
} 

Live example of all three | Live source

+0

Sí, la variable "a" es solo un ejemplo. Gracias – Sherzod

+0

Mi enfoque sería 'val (x, 'y.z.a')' (una sola cadena) –

+0

@ ŠimeVidas: Sí, estaba evitando la 'división ', pero no es caro. Agregué (y solucioné un error en el que pensé cuando me desperté esta mañana, y si * eso * no es patético, no sé qué es). –

1

Esto funciona :P

if ($($($(x).prop('y')).prop('z')).prop('a')) { 
    // code 
} 

en vivo de demostración:http://jsfiddle.net/Yw5th/

Es un patrón feo, pero al menos es una sola línea y los nombres de las propiedades no tienen que repetirse (a diferencia de x && x.y && x.y.z && ...).

+0

Me gusta especialmente cuando tienes nombres de variables largos. La única desventaja es que debe tener cuidado con los corchetes. – Sherzod

Cuestiones relacionadas