Acceso a objetos JavaScript anidados con string key


Tengo una estructura de datos como esta:

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

Y me gustaría acceder a los datos usando estas variables:

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

Part1name debe rellenarse con el valor de someObject.part1.name, que es "Part 1". Lo mismo con part2quantity que llenó con 60.

¿Hay alguna manera de lograr esto con javascript puro o jQuery?

Author: Paul Roub, 2011-06-27

28 answers

Acabo de hacer esto basado en algún código similar que ya tenía, parece que funciona:

Object.byString = function(o, s) {
    s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
    s = s.replace(/^\./, '');           // strip a leading dot
    var a = s.split('.');
    for (var i = 0, n = a.length; i < n; ++i) {
        var k = a[i];
        if (k in o) {
            o = o[k];
        } else {
            return;
        }
    }
    return o;
}

Uso::

Object.byString(someObj, 'part3[0].name');

Vea una demostración en funcionamiento en http://jsfiddle.net/alnitak/hEsys /

EDIT algunos han notado que este código lanzará un error si se pasa una cadena donde los índices más a la izquierda no corresponden a una entrada correctamente anidada dentro del objeto. Esta es una preocupación válida, pero en mi humilde opinión es mejor abordarla con un bloque try / catch al llamar, en lugar de tener esto función silenciosamente return undefined para un índice no válido.

 426
Author: Alnitak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-10 13:40:11

Esta es la solución que uso:

function resolve(path, obj=self, separator='.') {
    var properties = Array.isArray(path) ? path : path.split(separator)
    return properties.reduce((prev, curr) => prev && prev[curr], obj)
}

Ejemplo de uso:

// accessing property path on global scope
resolve("document.body.style.width")
// or
resolve("style.width", document.body)

// accessing array indexes
// (someObject has been defined in the question)
resolve("part3.0.size", someObject) // returns '10'

// accessing non-existent properties
// returns undefined when intermediate properties are not defined:
resolve('properties.that.do.not.exist', {hello:'world'})

// accessing properties with unusual keys by changing the separator
var obj = { object: { 'a.property.name.with.periods': 42 } }
resolve('object->a.property.name.with.periods', obj, '->') // returns 42

// accessing properties with unusual keys by passing a property name array
resolve(['object', 'a.property.name.with.periods'], obj) // returns 42

Limitaciones:

  • No puede usar corchetes ([]) para los índices de matriz-aunque especificar índices de matriz entre el token separador (por ejemplo, .) funciona bien como se muestra arriba.
 125
Author: speigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-15 00:59:02

Esto es ahora soportado por lodash usando _.get(obj, property). Véase https://lodash.com/docs#get

Ejemplo de los documentos:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// → 3

_.get(object, ['a', '0', 'b', 'c']);
// → 3

_.get(object, 'a.b.c', 'default');
// → 'default'
 113
Author: Ian Walker-Sperber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-08 20:59:00

Tendrías que analizar la cadena tú mismo:

function getProperty(obj, prop) {
    var parts = prop.split('.');

    if (Array.isArray(parts)) {
        var last = parts.pop(),
        l = parts.length,
        i = 1,
        current = parts[0];

        while((obj = obj[current]) && i < l) {
            current = parts[i];
            i++;
        }

        if(obj) {
            return obj[last];
        }
    } else {
        throw 'parts is not valid array';
    }
}

Esto requiere que también defina índices de matriz con notación de puntos:

var part3name1 = "part3.0.name";

Facilita el análisis.

DEMO

 61
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 13:46:31

También funciona para matrices / matrices dentro del objeto. Defensivo contra valores no válidos.

/**
 * Retrieve nested item from object/array
 * @param {Object|Array} obj
 * @param {String} path dot separated
 * @param {*} def default value ( if result undefined )
 * @returns {*}
 */
function path(obj, path, def){
    var i, len;

    for(i = 0,path = path.split('.'), len = path.length; i < len; i++){
        if(!obj || typeof obj !== 'object') return def;
        obj = obj[path[i]];
    }

    if(obj === undefined) return def;
    return obj;
}

//////////////////////////
//         TEST         //
//////////////////////////

var arr = [true, {'sp ace': true}, true]

var obj = {
  'sp ace': true,
  arr: arr,
  nested: {'dotted.str.ing': true},
  arr3: arr
}

shouldThrow(`path(obj, "arr.0")`);
shouldBeDefined(`path(obj, "arr[0]")`);
shouldBeEqualToNumber(`path(obj, "arr.length")`, 3);
shouldBeTrue(`path(obj, "sp ace")`);
shouldBeEqualToString(`path(obj, "none.existed.prop", "fallback")`, "fallback");
shouldBeTrue(`path(obj, "nested['dotted.str.ing'])`);
<script src="https://cdn.rawgit.com/coderek/e7b30bac7634a50ad8fd/raw/174b6634c8f57aa8aac0716c5b7b2a7098e03584/js-test.js"></script>
 38
Author: TheZver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-27 10:47:43

ES6 : Solo una línea en Vanila JS (devuelve null si no se encuentra en lugar de dar error):

'path.string'.split('.').reduce((p,c)=>p&&p[c]||null, MyOBJ)

O ejemplo:

'a.b.c'.split('.').reduce((p,c)=>p&&p[c]||null, {a:{b:{c:1}}})

Para una función lista para usar que también reconoce números falsos, 0 y negativos y acepta valores predeterminados como parámetro:

const resolvePath = (object, path, defaultValue) => path
   .split('.')
   .reduce((o, p) => o ? o[p] : defaultValue, object)

Ejemplo a utilizar:

resolvePath(window,'document.body') => <body>
resolvePath(window,'document.body.xyz') => undefined
resolvePath(window,'document.body.xyz', null) => null
resolvePath(window,'document.body.xyz', 1) => 1

Bono:

Para establecer una ruta (Solicitada por @ rob-gordon) puede usar:

const setPath = (object, path, value) => path
   .split('.')
   .reduce((o,p) => o[p] = path.split('.').pop() === p ? value : o[p] || {}, object)

Ejemplo:

let myVar = {}
setPath(myVar, 'a.b.c', 42) => 42
console.log(myVar) => {a: {b: {c: 42}}}

matriz de Acceso con []:

const resolvePath = (object, path, defaultValue) => path
   .split(/[\.\[\]\'\"]/)
   .filter(p => p)
   .reduce((o, p) => o ? o[p] : defaultValue, object)

Ejemplo

const myVar = {a:{b:[{c:1}]}}
resolvePath(myVar,'a.b[0].c') => 1
resolvePath(myVar,'a["b"][\'0\'].c') => 1
 26
Author: Adriano Spadoni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-19 19:05:09

Usando eval:

var part1name = eval("someObject.part1.name");

Wrap para devolver indefinido en caso de error

function path(obj, path) {
    try {
        return eval("obj." + path);
    } catch(e) {
        return undefined;
    }
}

Http://jsfiddle.net/shanimal/b3xTw /

Por favor, use el sentido común y la precaución cuando ejerza el poder de eval. Es un poco como un sable de luz, si lo enciendes hay un 90% de probabilidades de que cortes una extremidad. No es para todos.

 20
Author: Shanimal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-24 06:55:46

Puede obtener el valor de un miembro de objeto profundo con notación de puntos sin ninguna biblioteca JavaScript externa con el siguiente truco:

new Function('_', 'return _.' + path)(obj);

En su caso para obtener el valor de part1.name de someObject simplemente haga:

new Function('_', 'return _.part1.name')(someObject);

Aquí hay una demostración simple de fiddle: https://jsfiddle.net/harishanchu/oq5esowf /

 11
Author: Harish Anchu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-24 11:43:02

Aquí ofrezco más formas, que parecen más rápidas en muchos aspectos:

Opción 1: Dividir cadena en . o [o] o ' o ", invertirlo, saltar elementos vacíos.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var parts = path.split(/\[|\]|\.|'|"/g).reverse(), name; // (why reverse? because it's usually faster to pop off the end of an array)
    while (parts.length) { name=parts.pop(); if (name) origin=origin[name]; }
    return origin;
}

Opción 2 (la más rápida de todas, excepto eval): Exploración de caracteres de bajo nivel (sin regex/split/etc, solo una exploración de caracteres rápida). Nota: Este no admite comillas para índices.

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c = '', pc, i = 0, n = path.length, name = '';
    if (n) while (i<=n) ((c = path[i++]) == '.' || c == '[' || c == ']' || c == void 0) ? (name?(origin = origin[name], name = ''):(pc=='.'||pc=='['||pc==']'&&c==']'?i=n+2:void 0),pc=c) : name += c;
    if (i==n+2) throw "Invalid path: "+path;
    return origin;
} // (around 1,000,000+/- ops/sec)

Opción 3: (nuevo: la opción 2 se expandió para admitir cotizaciones, un poco más lenta, pero aún así rápido)

function getValue(path, origin) {
    if (origin === void 0 || origin === null) origin = self ? self : this;
    if (typeof path !== 'string') path = '' + path;
    var c, pc, i = 0, n = path.length, name = '', q;
    while (i<=n)
        ((c = path[i++]) == '.' || c == '[' || c == ']' || c == "'" || c == '"' || c == void 0) ? (c==q&&path[i]==']'?q='':q?name+=c:name?(origin?origin=origin[name]:i=n+2,name='') : (pc=='['&&(c=='"'||c=="'")?q=c:pc=='.'||pc=='['||pc==']'&&c==']'||pc=='"'||pc=="'"?i=n+2:void 0), pc=c) : name += c;
    if (i==n+2 || name) throw "Invalid path: "+path;
    return origin;
}

JSPerf: http://jsperf.com/ways-to-dereference-a-delimited-property-string/3

" eval(...) "is still king though (performance wise that is). Si tiene rutas de propiedad directamente bajo su control, no debería haber ningún problema con el uso de 'eval' (especialmente si se desea velocidad). Si tirando caminos de propiedad "sobre el cable" (en la línea!? lol: P), entonces sí, usa otra cosa para estar seguro. Sólo un idiota diría que nunca use "eval" en todos, ya que hay buenas razones cuando usarlo. Además, " Se usa en el analizador JSON de Doug Crockford."Si la entrada es segura, entonces no hay problemas en absoluto. Usa la herramienta correcta para el trabajo correcto, eso es todo.

 8
Author: James Wilkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:10

Creo que usted está pidiendo esto:

var part1name = someObject.part1.name;
var part2quantity = someObject.part2.qty;
var part3name1 =  someObject.part3[0].name;

Usted podría estar pidiendo esto:

var part1name = someObject["part1"]["name"];
var part2quantity = someObject["part2"]["qty"];
var part3name1 =  someObject["part3"][0]["name"];

Ambos funcionarán


O tal vez usted está pidiendo esto

var partName = "part1";
var nameStr = "name";

var part1name = someObject[partName][nameStr];

Finalmente podrías estar pidiendo esto

var partName = "part1.name";

var partBits = partName.split(".");

var part1name = someObject[partBits[0]][partBits[1]];
 7
Author: Hogan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-27 20:46:26

El enfoque de Speigg es muy ordenado y limpio, aunque encontré esta respuesta mientras buscaba la solución de acceder a las propiedades AngularJS scope scope por string path y con una pequeña modificación hace el trabajo:

$scope.resolve = function( path, obj ) {
    return path.split('.').reduce( function( prev, curr ) {
        return prev[curr];
    }, obj || this );
}

Simplemente coloque esta función en su controlador raíz y utilícela en cualquier ámbito secundario como este:

$scope.resolve( 'path.to.any.object.in.scope')
 6
Author: nesinervink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-26 12:22:42

Es un trazador de líneas con lodash.

const deep = { l1: { l2: { l3: "Hello" } } };
const prop = "l1.l2.l3";
const val = _.reduce(prop.split('.'), function(result, value) { return result ? result[value] : undefined; }, deep);
// val === "Hello"

O incluso mejor...

const val = _.get(deep, prop);

O la versión ES6 con reducir...

const val = prop.split('.').reduce((r, val) => { return r ? r[val] : undefined; }, deep);

Plunkr

 4
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-18 00:50:51

Todavía no he encontrado un paquete para hacer todas las operaciones con una ruta de cadena, así que terminé escribiendo mi propio paquete rápido que admite las operaciones insert(), get() (con retorno predeterminado), set() y remove ().

Puede usar notación de puntos, corchetes, índices de números, propiedades de números de cadena y claves con caracteres que no sean de palabra. Uso Simple abajo:

> var jsocrud = require('jsocrud');

...

// Get (Read) ---
> var obj = {
>     foo: [
>         {
>             'key w/ non-word chars': 'bar'
>         }
>     ]
> };
undefined

> jsocrud.get(obj, '.foo[0]["key w/ non-word chars"]');
'bar'

Https://www.npmjs.com/package/jsocrud

Https://github.com/vertical-knowledge/jsocrud

 3
Author: Kyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-25 01:32:44

Función simple, que permite una ruta de cadena o matriz.

function get(obj, path) {
  if(typeof path === 'string') path = path.split('.');

  if(path.length === 0) return obj;
  return get(obj[path[0]], path.slice(1));
}

const obj = {a: {b: {c: 'foo'}}};

console.log(get(obj, 'a.b.c')); //foo

O

console.log(get(obj, ['a', 'b', 'c'])); //foo
 3
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-26 14:42:36

Ahora hay un módulo npm para hacer esto: https://github.com/erictrinh/safe-access

Ejemplo de uso:

var access = require('safe-access');
access(very, 'nested.property.and.array[0]');
 2
Author: caleb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-13 18:56:11

Por si acaso, cualquiera que visite esta pregunta en 2017 o más tarde y busque una forma fácil de recordar , aquí hay una elaborada publicación de blog sobre Acceder a Objetos Anidados en JavaScript sin ser engañado por

No se puede leer la propiedad ' foo ' de undefined error

Accede a Objetos Anidados Usando Array Reduce

Tomemos este ejemplo estructura

const user = {
    id: 101,
    email: '[email protected]',
    personalInfo: {
        name: 'Jack',
        address: [{
            line1: 'westwish st',
            line2: 'washmasher',
            city: 'wallas',
            state: 'WX'
        }]
    }
}

Para poder acceder a matrices anidadas, puede escribir su propia matriz reducir útil.

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'address', 0, 'city']);
// this will return the city from the first address item.

También hay una excelente biblioteca mínima de manejo de tipos typy que hace todo esto por usted.

Con typy, su código se verá así

const city = t(user, 'personalInfo.address[0].city').safeObject;

Descargo de responsabilidad: Soy el autor de este paquete.

 2
Author: Dinesh Pandiyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-08 13:01:53

Esto probablemente nunca verá la luz del día... pero aquí está de todos modos.

  1. Reemplazar [] sintaxis de corchetes con .
  2. Dividir en ' carácter
  3. Eliminar cadenas en blanco
  4. Encuentra el camino (de lo contrario undefined)

// "one liner" (ES6)

const deep_value = (obj, path) => 
  path
    .replace(/\[|\]\.?/g, '.')
    .split('.')
    .filter(s => s)
    .reduce((acc, val) => acc && acc[val], obj);
    
// ... and that's it.

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }
        // ...
    ]
};

console.log(deep_value(someObject, "part1.name"));               // Part 1
console.log(deep_value(someObject, "part2.qty"));                // 60
console.log(deep_value(someObject, "part3[0].name"));            // Part 3A
 2
Author: Nick Grealy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 02:50:48
/**
 * Access a deep value inside a object 
 * Works by passing a path like "foo.bar", also works with nested arrays like "foo[0][1].baz"
 * @author Victor B. https://gist.github.com/victornpb/4c7882c1b9d36292308e
 * Unit tests: http://jsfiddle.net/Victornpb/0u1qygrh/
 */
function getDeepVal(obj, path) {
    if (typeof obj === "undefined" || obj === null) return;
    path = path.split(/[\.\[\]\"\']{1,2}/);
    for (var i = 0, l = path.length; i < l; i++) {
        if (path[i] === "") continue;
        obj = obj[path[i]];
        if (typeof obj === "undefined" || obj === null) return;
    }
    return obj;
}

Funciona con

getDeepVal(obj,'foo.bar')
getDeepVal(obj,'foo.1.bar')
getDeepVal(obj,'foo[0].baz')
getDeepVal(obj,'foo[1][2]')
getDeepVal(obj,"foo['bar'].baz")
getDeepVal(obj,"foo['bar']['baz']")
getDeepVal(obj,"foo.bar.0.baz[1]['2']['w'].aaa[\"f\"].bb")
 1
Author: Vitim.us,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-29 19:51:35

Mientras que reducir es bueno, me sorprende que nadie utiliza forEach:

function valueForKeyPath(obj, path){
        const keys = path.split('.');
        keys.forEach((key)=> obj = obj[key]);
        return obj;
    };

Prueba

 1
Author: Flavien Volken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-15 14:03:14

Si necesita acceder a diferentes claves anidadas sin saberlo en el momento de la codificación (será trivial abordarlas), puede usar el accesor de notación de matriz:

var part1name = someObject['part1']['name'];
var part2quantity = someObject['part2']['qty'];
var part3name1 =  someObject['part3'][0]['name'];

Son equivalentes al accessor de notación de punto y pueden variar en tiempo de ejecución, por ejemplo:

var part = 'part1';
var property = 'name';

var part1name = someObject[part][property];

Es equivalente a

var part1name = someObject['part1']['name'];

O

var part1name = someObject.part1.name;

Espero que esto responda a su pregunta...

EDITAR

No usaré una cadena para mantener una especie de consulta xpath para acceder a una valor del objeto. Como tienes que llamar a una función para analizar la consulta y recuperar el valor, seguiría otra ruta (no:

var part1name = function(){ return this.part1.name; }
var part2quantity = function() { return this['part2']['qty']; }
var part3name1 =  function() { return this.part3[0]['name'];}

// usage: part1name.apply(someObject);

O, si no está cómodo con el aplique el método

var part1name = function(obj){ return obj.part1.name; }
var part2quantity = function(obj) { return obj['part2']['qty']; }
var part3name1 =  function(obj) { return obj.part3[0]['name'];}

// usage: part1name(someObject);

Las funciones son más cortas, más claras, el intérprete las comprueba por usted en busca de errores de sintaxis, etc.

Por cierto, siento que una simple tarea hecha en el momento adecuado será suficiente...

 0
Author: Eineki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-27 11:35:18

Acaba de tener la misma pregunta recientemente y se ha utilizado con éxito https://npmjs.org/package/tea-properties que también set objetos/matrices anidados:

Obtener:

var o = {
  prop: {
    arr: [
      {foo: 'bar'}
    ]
  }
};

var properties = require('tea-properties');
var value = properties.get(o, 'prop.arr[0].foo');

assert(value, 'bar'); // true

Conjunto:

var o = {};

var properties = require('tea-properties');
properties.set(o, 'prop.arr[0].foo', 'bar');

assert(o.prop.arr[0].foo, 'bar'); // true
 0
Author: abernier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-04 00:41:22

Las soluciones aquí son solo para acceder a las claves profundamente anidadas. Necesitaba uno para acceder, agregar, modificar y eliminar las claves. Esto es lo que se me ocurrió:

var deepAccessObject = function(object, path_to_key, type_of_function, value){
    switch(type_of_function){
        //Add key/modify key
        case 0: 
            if(path_to_key.length === 1){
                if(value)
                    object[path_to_key[0]] = value;
                return object[path_to_key[0]];
            }else{
                if(object[path_to_key[0]])
                    return deepAccessObject(object[path_to_key[0]], path_to_key.slice(1), type_of_function, value);
                else
                    object[path_to_key[0]] = {};
            }
            break;
        //delete key
        case 1:
            if(path_to_key.length === 1){
                delete object[path_to_key[0]];
                return true;
            }else{
                if(object[path_to_key[0]])
                    return deepAccessObject(object[path_to_key[0]], path_to_key.slice(1), type_of_function, value);
                else
                    return false;
            }
            break;
        default:
            console.log("Wrong type of function");
    }
};
  • path_to_key: ruta en un array. Puede reemplazarlo por su string_path.split(".").
  • type_of_function: 0 para acceder(no pase ningún valor a value), 0 para agregar y modificar. 1 para eliminar.
 0
Author: ayushgp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-23 09:45:46

En lugar de una cadena, se puede usar una matriz que direccione objetos anidados y matrices, por ejemplo: ["my_field", "another_field", 0, "last_field", 10]

Aquí hay un ejemplo que cambiaría un campo basado en esta representación de matriz. Estoy usando algo así en react.js para campos de entrada controlados que cambian el estado de las estructuras anidadas.

let state = {
        test: "test_value",
        nested: {
            level1: "level1 value"
        },
        arr: [1, 2, 3],
        nested_arr: {
            arr: ["buh", "bah", "foo"]
        }
    }

function handleChange(value, fields) {
    let update_field = state;
    for(var i = 0; i < fields.length - 1; i++){
        update_field = update_field[fields[i]];
    }
    update_field[fields[fields.length-1]] = value;
}

handleChange("update", ["test"]);
handleChange("update_nested", ["nested","level1"]);
handleChange(100, ["arr",0]);
handleChange('changed_foo', ["nested_arr", "arr", 3]);
console.log(state);
 0
Author: Jodo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-25 08:12:18

Basado en una respuesta anterior, he creado una función que también puede manejar corchetes. Pero no hay puntos dentro de ellos debido a la división.

function get(obj, str) {
  return str.split(/\.|\[/g).map(function(crumb) {
    return crumb.replace(/\]$/, '').trim().replace(/^(["'])((?:(?!\1)[^\\]|\\.)*?)\1$/, (match, quote, str) => str.replace(/\\(\\)?/g, "$1"));
  }).reduce(function(obj, prop) {
    return obj ? obj[prop] : undefined;
  }, obj);
}
 0
Author: Vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-01 12:44:48

// (IE9+) Two steps

var pathString = "[0]['property'].others[3].next['final']";
var obj = [{
  property: {
    others: [1, 2, 3, {
      next: {
        final: "SUCCESS"
      }
    }]
  }
}];

// Turn string to path array
var pathArray = pathString
    .replace(/\[["']?([\w]+)["']?\]/g,".$1")
    .split(".")
    .splice(1);

// Add object prototype method
Object.prototype.path = function (path) {
  try {
    return [this].concat(path).reduce(function (f, l) {
      return f[l];
    });
  } catch (e) {
    console.error(e);
  }
};

// usage
console.log(obj.path(pathArray));
console.log(obj.path([0,"doesNotExist"]));
 0
Author: Oboo Chin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-23 12:37:22

Trabajando con Underscore's property o propertyOf:

var test = {
  foo: {
    bar: {
      baz: 'hello'
    }
  }
}
var string = 'foo.bar.baz';


// document.write(_.propertyOf(test)(string.split('.')))

document.write(_.property(string.split('.'))(test));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

Buena Suerte...

 0
Author: Akash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-22 11:49:45

¿Qué pasa con esta solución:

setJsonValue: function (json, field, val) {
  if (field !== undefined){
    try {
      eval("json." + field + " = val");
    }
    catch(e){
      ;
    }
  }  
}

Y este, para obtener:

getJsonValue: function (json, field){
  var value = undefined;
  if (field !== undefined) {
    try {
      eval("value = json." + field);
    } 
    catch(e){
      ;
    }
  }
  return value;
};

Probablemente algunos los considerarán inseguros, pero deben ser mucho más rápidos entonces, analizando la cadena.

 -1
Author: Jonan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-04 19:54:04

Construyendo a partir de la respuesta de Alnitak:

if(!Object.prototype.byString){
  //NEW byString which can update values
Object.prototype.byString = function(s, v, o) {
  var _o = o || this;
      s = s.replace(/\[(\w+)\]/g, '.$1'); // CONVERT INDEXES TO PROPERTIES
      s = s.replace(/^\./, ''); // STRIP A LEADING DOT
      var a = s.split('.'); //ARRAY OF STRINGS SPLIT BY '.'
      for (var i = 0; i < a.length; ++i) {//LOOP OVER ARRAY OF STRINGS
          var k = a[i];
          if (k in _o) {//LOOP THROUGH OBJECT KEYS
              if(_o.hasOwnProperty(k)){//USE ONLY KEYS WE CREATED
                if(v !== undefined){//IF WE HAVE A NEW VALUE PARAM
                  if(i === a.length -1){//IF IT'S THE LAST IN THE ARRAY
                    _o[k] = v;
                  }
                }
                _o = _o[k];//NO NEW VALUE SO JUST RETURN THE CURRENT VALUE
              }
          } else {
              return;
          }
      }
      return _o;
  };

}

Esto le permite establecer un valor también!

He creado un paquete npm y github con esto también

 -1
Author: Tamb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-15 21:40:23