Snippet: Accediendo de forma elegante a una propiedad profunda en un objeto Javascript

13 Mar 2017

El problema

Ocurre a menudo que, cuando necesitamos acceder al valor de una propiedad en un objeto Javascript, si ésta no existe, obtenemos un error. Para evitarlo, lo habitual es recorrer la cadena completa, paso a paso, para ir garantizando su consistencia.

Supongamos este objeto:

const user = {
    fullName: 'Bob Smith',    
    location: {
        country: 'USA',
        state: 'Iowa',
        address: {
            type: 'building',
            street: 'SpringFlowers',
            number: 3
        }
    } 
};

Si intentamos acceder a una propiedad anidada a través de un ancestro que no existe, el intérprete nos devuelve el error:

user.phone.mobile; // Uncaught TypeError: Cannot read property 'mobile' of undefined

Para alcanzar de forma segura a una propiedad, debemos recorrer toda su cadena ancestral comprobando en cada paso que éstos existen. Por lo general, aplicamos para ello una evaluación perezosa de tipo cortocircuito:

user && user.location.address.street; // SpringFlowers

Como se puede ver, esta forma de acceso es poco práctica: a mayor nivel de profundidad, mayor cadena de evaluación.

Objetivo

Para solucionar este escenario, vamos a crear una función o método que haga el trabajo sucio por nosotros, dejándonos en nuestro códigos una evaluación más simple y legible.

Cuándo puede ser útil

  • Tenemos objetos creados dinámicamente y queremos obtener el valor de una propiedad anidada que, puede o no, existir.
  • Queremos mejorar la legibilidad de nuestro código fuente utilizando una función independiente para acceder a nuestras propiedades.

Soporte y dependencias

  • No es necesario el uso de ninguna dependencia.

El código.

Versión ES5

/**
 * Get a nested object property value
 * Checks for a nested object property and returns its value.
 * @param   {object}    obj     An object given
 * @param   {string}    key     The needed key
 * @return  {string}            The value of that key.  
 */
var getProp = function (obj, key) {
    return key.split('.').reduce( function (o, x) {
        return (typeof o == "undefined" || o === null) ? o : o[x];
    }, obj);
};

Versión ES6

const getProp = (obj, key) =>
    key.split('.').reduce( (o, x) =>
        (typeof o == "undefined" || o === null) ? o : o[x]
    , obj);

Funcionamiento

Nuestra función toma dos parámetros: el objeto sobre el que queremos actuar, y una cadena que marca el camino de la propiedad requerida.

La idea base es dividir esa cadena de propiedades en un array para ir comprobando, de forma iterativa, si ésta existe en nuestro objeto.

Ejemplo de uso, el código completo

Basándonos en los ejemplos anteriores, presentamos aquí todo el código completo interactivo:

// The function
const getProp = (obj, key) =>
    key.split('.').reduce( (o, x) =>
        (typeof o == "undefined" || o === null) ? o : o[x]
    , obj);

// Our mock object
const user = {
    fullName: 'Bob Smith',    
    location: {
        country: 'USA',
        state: 'Iowa',
        address: {
            type: 'building',
            street: 'SpringFlowers',
            number: 3
        }
    } 
};

// Implementation
getProp(user, 'phone.mobile'); //undefined
getProp(user, 'location.address.street'); //SpringFlowers
Más:

Solo un marciano comentando!

  1. Elkin Bernal

    Muuuy útil, cómo siempre.

    Muuuchas gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *