Accès aux objets JavaScript imbriqués avec une clé de chaîne

J'ai une structure de données comme ceci :

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'
        }
    ]
};

Et je voudrais accéder aux données en utilisant ces variables:

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

Part1name doit être rempli avec la valeur de someObject.part1.name, qui est "Part 1". Même chose avec part2quantity qui a rempli avec 60.

Existe-t-il de toute façon pour y parvenir avec JavaScript pur ou JQuery?

321
demandé sur Paul Roub 2011-06-27 14:25:02

28 réponses

Je viens de le faire basé sur un code similaire que j'avais déjà, il semble fonctionner:

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;
}

Utilisation::

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

Voir une démo de travail à http://jsfiddle.net/alnitak/hEsys/

EDIT certains ont remarqué que ce code déclenchera une erreur si une chaîne est passée où les index les plus à gauche ne correspondent pas à une entrée correctement imbriquée dans l'objet. C'est une préoccupation VALIDE, mais à mon humble avis, il vaut mieux traiter avec un bloc try / catch lors de l'appel, plutôt que d'avoir ceci la fonction renvoie silencieusement undefined pour un index invalide.

426
répondu Alnitak 2016-10-10 13:40:11

C'est la solution que j'utilise:

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

Exemple d'utilisation:

// 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

Limites:

  • ne peut pas utiliser de parenthèses ([]) pour les indices de tableau-bien que la spécification d'indices de tableau entre le jeton de séparation (par exemple, .) fonctionne correctement comme indiqué ci-dessus.
125
répondu speigg 2018-08-15 00:59:02

Ceci est maintenant pris en charge par lodash en utilisant _.get(obj, property). Voir https://lodash.com/docs#get

Exemple des documents:

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
répondu Ian Walker-Sperber 2015-07-08 20:59:00

Vous devrez analyser la chaîne vous-même:

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';
    }
}

Cela nécessitait que vous définissiez également des index de tableau avec une notation par points:

var part3name1 = "part3.0.name";

Cela facilite l'analyse.

DÉMO

61
répondu Felix Kling 2015-12-04 13:46:31

Fonctionne pour les tableaux / tableaux à l'intérieur de l'objet. Défensif contre les valeurs invalides.

/**
 * 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
répondu TheZver 2016-03-27 10:47:43

ES6 : une seule ligne dans Vanila js (elle renvoie null si ne trouve pas au lieu de donner une erreur):

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

Ou exemple:

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

Pour une fonction prête à l'emploi qui reconnaît également le nombre faux, 0 et négatif et accepte les valeurs par défaut comme paramètre:

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

Exemple à utiliser:

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

Bonus:

À set un chemin d'accès (Demandé par @rob gordon), vous pouvez utiliser:

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

Exemple:

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

tableau d'Accès avec []:

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

Exemple

const myVar = {a:{b:[{c:1}]}}
resolvePath(myVar,'a.b[0].c') => 1
resolvePath(myVar,'a["b"][\'0\'].c') => 1
26
répondu Adriano Spadoni 2017-09-19 19:05:09

En utilisant eval:

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

Wrap pour retourner undefined en cas d'erreur

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

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

Veuillez faire preuve de bon sens et de prudence lorsque vous utilisez le pouvoir d'eval. C'est un peu comme un sabre léger, si vous l'allumez, il y a 90% de chances que vous coupiez un membre. Ce n'est pas pour tout le monde.

20
répondu Shanimal 2014-04-24 06:55:46

Vous pouvez obtenir la valeur d'un membre d'objet profond avec une notation par points sans bibliothèque JavaScript externe avec l'astuce suivante:

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

Dans votre cas pour obtenir la valeur de part1.name de someObject Faites simplement:

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

Voici une simple démo de violon: https://jsfiddle.net/harishanchu/oq5esowf/

11
répondu Harish Anchu 2016-02-24 11:43:02

Ici, j'offre plus de moyens, qui semblent plus rapides à bien des égards:

Option 1: diviser la chaîne sur . ou [ ou] ou 'ou", inversez-le, sautez les éléments vides.

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;
}

Option 2 (la plus rapide de toutes, sauf eval): Analyse de caractères de bas niveau (Pas de regex / split/etc, juste une analyse de caractères rapide). Note: celui-ci ne prend pas en charge les guillemets pour les index.

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)

Option 3: (nouveau : option 2 développée pour prendre en charge les guillemets-un peu plus lent, mais toujours rapide)

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(...) "est toujours roi (performance sage qui est). Si vous avez des chemins de propriétés directement sous votre contrôle, il ne devrait pas y avoir de problèmes avec l'utilisation de 'eval' (surtout si la vitesse est souhaitée). Si vous tirez des chemins de propriété "sur le fil" (sur la ligne!? lol: P), alors oui, utilisez autre chose pour être sûr. Seul un idiot dirait de ne jamais utiliser "eval" à tout, car il y a de bonnes raisons quand l'utiliser. En outre, "il est utilisé dans L'analyseur JSON de Doug Crockford."Si l'entrée est sûre, alors pas de problèmes du tout . Utiliser le bon outil pour le bon travail, c'est tout.

8
répondu James Wilkins 2017-05-23 11:55:10

Je pense que vous demandez ceci:

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

Vous pourriez demander ceci:

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

Qui fonctionneront tous les deux


Ou peut-être que vous demandez cela

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

var part1name = someObject[partName][nameStr];

Enfin, vous pourriez demander ceci

var partName = "part1.name";

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

var part1name = someObject[partBits[0]][partBits[1]];
7
répondu Hogan 2011-06-27 20:46:26

L'approche de Speigg est très soignée et propre, bien que j'ai trouvé cette réponse en cherchant la solution d'accéder aux propriétés AngularJS $scope par chemin de chaîne et avec une petite modification, il fait le travail:

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

Placez simplement cette fonction dans votre contrôleur racine et utilisez-la n'importe quelle portée enfant comme ceci:

$scope.resolve( 'path.to.any.object.in.scope')
6
répondu nesinervink 2015-02-26 12:22:42

C'est un one liner avec 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"

Ou encore mieux...

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

Ou version ES6 avec réduction...

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

Plunkr

4
répondu James 2017-11-18 00:50:51

Je n'ai pas encore trouvé de paquet pour faire toutes les opérations avec un chemin de chaîne, donc j'ai fini par écrire mon propre petit paquet rapide qui supporte les opérations insert (), get () (avec RETOUR par défaut), set () et remove ().

Vous pouvez utiliser la notation par points, les parenthèses, les indices de nombres, les propriétés de nombre de chaînes et les clés avec des caractères non word. Simple d'utilisation ci-dessous:

> 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
répondu Kyle 2015-04-25 01:32:44

Fonction Simple, permettant un chemin de chaîne ou de tableau.

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

Ou

console.log(get(obj, ['a', 'b', 'c'])); //foo
3
répondu Ben 2016-12-26 14:42:36

Il y a un module npm maintenant pour faire ceci: https://github.com/erictrinh/safe-access

Exemple d'utilisation:

var access = require('safe-access');
access(very, 'nested.property.and.array[0]');
2
répondu caleb 2014-06-13 18:56:11

Juste au cas où, quelqu'un visite cette question en 2017 ou plus tard et cherche un moyen facile à retenir, Voici un article de blog élaboré sur accédant aux objets imbriqués en JavaScript sans être bamboozled par

Impossible de lire la propriété 'foo' undefined erreur

Accédez Aux Objets Imbriqués En Utilisant Array Reduce

Prenons cet exemple de structure

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

Pour pouvoir accéder aux tableaux imbriqués, vous pouvez écrire votre propre tableau réduire util.

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.

Il existe également une excellente bibliothèque minimale de gestion des types typy qui fait tout cela pour vous.

Avec typy, votre code ressemblera à ceci

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

Avertissement: je suis l'auteur de ce paquet.

2
répondu Dinesh Pandiyan 2018-07-08 13:01:53

Cela ne verra probablement jamais le jour... mais ici, il est de toute façon.

  1. remplacez [] la syntaxe des crochets par .
  2. diviser sur ' caractère
  3. supprimer les chaînes vides
  4. trouver le chemin (sinon 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
répondu Nick Grealy 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;
}

Fonctionne avec

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
répondu Vitim.us 2016-09-29 19:51:35

Alors que réduire est bon, je suis surpris que personne n'utilise forEach:

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

Essai

1
répondu Flavien Volken 2017-12-15 14:03:14

Si vous avez besoin d'accéder à différentes clés imbriquées sans le savoir au moment du codage (il sera trivial de les traiter), vous pouvez utiliser l'accesseur de notation de tableau:

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

Ils sont équivalents à l'accesseur de notation de point et peuvent varier au moment de l'exécution, par exemple:

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

var part1name = someObject[part][property];

Est équivalent à

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

Ou

var part1name = someObject.part1.name;

J'espère que cette adresse votre question...

Modifier

Je n'utiliserai pas une chaîne pour gérer une sorte de XPath query pour accéder à un la valeur de l'objet. Comme vous devez appeler une fonction pour analyser la requête et récupérer la valeur, je suivrais un autre chemin (pas:

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);

Ou, si vous êtes mal à l'aise avec les appliquer méthode

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);

Les fonctions sont plus courtes, plus claires, l'interpréteur les vérifie pour vous pour les erreurs de syntaxe et ainsi de suite.

En passant, je pense qu'une simple affectation faite au bon moment sera suffisante...

0
répondu Eineki 2011-06-27 11:35:18

Vient d'avoir la même question récemment et utilisé avec succès https://npmjs.org/package/tea-properties qui aussi set Objet/tableaux imbriqués:

Obtenir:

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

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

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

Ensemble:

var o = {};

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

assert(o.prop.arr[0].foo, 'bar'); // true
0
répondu abernier 2013-11-04 00:41:22

Les solutions ici sont juste pour accéder aux clés profondément imbriquées. J'en avais besoin pour accéder, ajouter, modifier et supprimer les clés. C'est ce que je suis venu avec:

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: chemin dans un tableau. Vous pouvez le remplacer par votre string_path.split(".").
  • type_of_function: 0 pour accéder(ne passez aucune valeur à value), 0 pour ajouter et modifier. 1 pour la suppression.
0
répondu ayushgp 2016-06-23 09:45:46

Au lieu d'une chaîne, Un tableau peut être utilisé pour adresser des objets imbriqués et des tableaux, par exemple: ["my_field", "another_field", 0, "last_field", 10]

Voici un exemple qui modifierait un champ basé sur cette représentation de tableau. J'utilise quelque chose comme ça dans react.js pour les champs d'entrée contrôlés qui modifient l'état des structures imbriquées.

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
répondu Jodo 2017-10-25 08:12:18

Sur la base d'une réponse précédente, j'ai créé une fonction qui peut également gérer les parenthèses. Mais pas de points à l'intérieur en raison de la scission.

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
répondu Vincent 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
répondu Oboo Chin 2018-02-23 12:37:22

Travailler avec Underscore's property ou 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>

Bonne Chance...

0
répondu Akash 2018-06-22 11:49:45

Qu'en est-il de cette solution:

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

Et celui-ci, pour obtenir:

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

Probablement certains les considéreront comme dangereux, mais ils doivent être beaucoup plus rapides alors, en analysant la chaîne.

-1
répondu Jonan Georgiev 2013-12-04 19:54:04

Construire à partir de la réponse D'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;
  };

}

Cela vous permet de définir une valeur aussi bien!

, j'ai créé un mnp package et github avec ce même

-1
répondu Tamb 2017-08-15 21:40:23