web-dev-qa-db-fra.com

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

J'ai une structure de données comme celle-ci:

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

nom_partie doit être renseigné avec la valeur de someObject.part1.name, qui correspond à «Partie 1». Même chose avec la quantité de part2 qui a rempli de 60.

Y a-t-il un moyen d'y parvenir avec du javascript pur ou avec JQuery?

348
Komaruloh

Je viens de le créer en me basant 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;
}

Usage::

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

Voir une démonstration de travail sur http://jsfiddle.net/alnitak/hEsys/

EDIT certains ont remarqué que ce code jetterait une erreur en cas de transmission d'une chaîne où les index les plus à gauche ne correspondent pas à une entrée correctement imbriquée dans l'objet. Ceci est une préoccupation valable, mais il est préférable de s’adresser à IMHO avec un bloc try / catch lors de l’appel, plutôt que de laisser cette fonction renvoyer en silence undefined pour un index incorrect.

452
Alnitak

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:

  • Impossible d'utiliser des crochets ([]) pour les index de tableau - bien que spécifier des index de tableau entre le jeton séparateur (par exemple, .) fonctionne correctement, comme indiqué ci-dessus. 
140
speigg

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

Exemple tiré de la documentation:

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'
131
Ian Walker-Sperber

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

Pour cela, vous devez également définir des index de tableau avec une notation par points:

var part3name1 = "part3.0.name";

Cela facilite l'analyse.

D&EACUTE;MO

61
Felix Kling

Fonctionne aussi pour les tableaux/tableaux à l'intérieur de l'objet.

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

39
TheZver

ES6 : Une seule ligne dans Vanila JS (elle renvoie null si elle 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 les nombres faux, 0 et négatifs et accepte les valeurs par défaut en tant que 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

Prime:

Pour définir un chemin (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}}}

Accéder au tableau 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
34
Adriano Spadoni

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/

Faites preuve de bon sens et de prudence lorsque vous utilisez le pouvoir d’eval. C'est un peu comme un sabre laser. Si vous l'allumez, vous avez 90% de chances de vous trancher un membre. Ce n'est pas pour tout le monde.

21
Shanimal

Vous pouvez obtenir la valeur d'un membre d'objet profond avec la notation pointée sans aucune bibliothèque JavaScript externe avec la simple astuce suivante:

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

Dans votre cas, pour obtenir la valeur de part1.name à partir de someObject, il suffit de:

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

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

14
Harish Anchu

Ici, je propose plus de moyens, qui semblent plus rapides à bien des égards:

Option 1: scinder la chaîne. ou [ou] ou 'ou ", inversez-le, ignorez 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, à l'exception de eval): analyse des caractères de bas niveau (pas de regex/split/etc, juste une analyse rapide des caractères) .Remarque: 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: (new: option 2 étendue 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 (en termes de performances). Si vous avez des chemins de propriété directement sous votre contrôle, l'utilisation de 'eval' ne devrait poser aucun problème (surtout si vous souhaitez utiliser la vitesse). 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" du tout, car il ya 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ème du tout. Utilisez le bon outil pour le bon travail, c'est tout.

7
James Wilkins

Cela ne verra probablement jamais la lumière du jour ... mais le voilà quand même.

  1. Remplacer la syntaxe de crochet [] par .
  2. Découper le caractère .
  3. Supprimer les chaînes vierges
  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

7
Nick Grealy

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"];

Ce qui fonctionnera


Ou peut-être que vous demandez ceci

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

var part1name = someObject[partName][nameStr];

Enfin, vous pourriez demander cela

var partName = "part1.name";

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

var part1name = someObject[partBits[0]][partBits[1]];
6
Hogan

L'approche de Speigg est très soignée et nette, même si j'ai trouvé cette réponse tout en cherchant la solution pour accéder aux propriétés de la portée AngularJS $ par chemin de chaîne et avec un peu de modification, cela fonctionne:

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

Il suffit de placer cette fonction dans votre contrôleur racine et de l’utiliser avec n’importe quelle portée enfant comme celle-ci:

$scope.resolve( 'path.to.any.object.in.scope')
6
nesinervink

C'est un paquebot 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 même 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

5
James

Juste au cas où quiconque visiterait cette question en 2017 ou plus tard et recherchant un moyen facile à mémoriser, voici un article de blog élaboré sur Accès aux objets imbriqués en JavaScript sans être embrouillé 

Impossible de lire la propriété 'foo' d'une erreur non définie

Accéder aux objets imbriqués à l'aide de Array Réduire

Prenons cet exemple de structure

const user = {
    id: 101,
    email: '[email protected]',
    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éduisez 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 type typy qui fait tout cela pour vous.

Avec typy, votre code ressemblera à ceci

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

Disclaimer: Je suis l'auteur de ce paquet.

4
Dinesh Pandiyan

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

Vous pouvez utiliser la notation par points, les crochets, les index de nombre, les propriétés de numéro de chaîne et les clés avec des caractères autres que Word. Utilisation simple 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
Kyle

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

OR

console.log(get(obj, ['a', 'b', 'c'])); //foo
3
Ben
/**
 * 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;
}

Marche 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")
2
Vitim.us

Il existe maintenant un module npm pour cela: https://github.com/erictrinh/safe-access

Exemple d'utilisation:

var access = require('safe-access');
access(very, 'nested.property.and.array[0]');
2
caleb

Bien que réduire, c'est bien, je suis surpris que personne ne l'ait utiliséChaque:

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

Test

1
Flavien Volken

Utilisation de 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
Akash

L'extension de Mohamad Hamouday 'Answer remplira les clés manquantes

function Object_Manager(obj, Path, value, Action, strict) 
{
    try
    {
        if(Array.isArray(Path) == false)
        {
            Path = [Path];
        }

        let level = 0;
        var Return_Value;
        Path.reduce((a, b)=>{
            console.log(level,':',a, '|||',b)
            if (!strict){
              if (!(b in a)) a[b] = {}
            }


            level++;
            if (level === Path.length)
            {
                if(Action === 'Set')
                {
                    a[b] = value;
                    return value;
                }
                else if(Action === 'Get')
                {
                    Return_Value = a[b];
                }
                else if(Action === 'Unset')
                {
                    delete a[b];
                }
            } 
            else 
            {
                return a[b];
            }
        }, obj);
        return Return_Value;
    }

    catch(err)
    {
        console.error(err);
        return obj;
    }
}

Exemple


obja = {
  "a": {
    "b":"nom"
  }
}

// Set
path = "c.b" // Path does not exist
Object_Manager(obja,path.split('.'), 'test_new_val', 'Set', false);

// Expected Output: Object { a: Object { b: "nom" }, c: Object { b: "test_new_value" } }

0
sam

Sur la base d’une réponse précédente, j’ai créé une fonction qui peut également gérer les crochets. 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
Vincent

Inspiré par la réponse de @ webjay: https://stackoverflow.com/a/46008856/4110122

J'ai créé cette fonction que vous pouvez utiliser pour Get/Set/Unset n’importe quelle valeur dans un objet

function Object_Manager(obj, Path, value, Action) 
{
    try
    {
        if(Array.isArray(Path) == false)
        {
            Path = [Path];
        }

        let level = 0;
        var Return_Value;
        Path.reduce((a, b)=>{
            level++;
            if (level === Path.length)
            {
                if(Action === 'Set')
                {
                    a[b] = value;
                    return value;
                }
                else if(Action === 'Get')
                {
                    Return_Value = a[b];
                }
                else if(Action === 'Unset')
                {
                    delete a[b];
                }
            } 
            else 
            {
                return a[b];
            }
        }, obj);
        return Return_Value;
    }

    catch(err)
    {
        console.error(err);
        return obj;
    }
}

Pour l'utiliser:

 // Set
 Object_Manager(Obj,[Level1,Level2,Level3],New_Value, 'Set');

 // Get
 Object_Manager(Obj,[Level1,Level2,Level3],'', 'Get');

 // Unset
 Object_Manager(Obj,[Level1,Level2,Level3],'', 'Unset');
0
Mohamad Hamouday

// (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
Oboo Chin

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

Voici un exemple qui modifierait un champ en fonction de cette représentation sous forme de tableau. J'utilise quelque chose comme ça dans react.js pour les champs d'entrée contrôlés qui changent 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
Jodo

Les solutions présentées ici ne servent qu'à accéder aux clés profondément imbriquées. J'avais besoin d'un pour accéder, ajouter, modifier et supprimer les clés. Voici 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 supprimer.
0
ayushgp

Je développe une boutique en ligne avec React. J'ai essayé de modifier les valeurs dans l'objet d'état copié pour mettre à jour l'état d'origine avec cet objet lors de l'envoi. Les exemples ci-dessus n'ont pas fonctionné pour moi, car la plupart d'entre eux modifient la structure d'un objet copié. J'ai trouvé un exemple de travail de la fonction d'accès et de modification des valeurs des propriétés d'objet imbriquées profondes: https://lowrey.me/create-an-object-by-path-in-javascript-2/ le voici :

const createPath = (obj, path, value = null) => {
  path = typeof path === 'string' ? path.split('.') : path;
  let current = obj;
  while (path.length > 1) {
    const [head, ...tail] = path;
    path = tail;
    if (current[head] === undefined) {
      current[head] = {};
    }
    current = current[head];
  }
  current[path[0]] = value;
  return obj;
};
0
Dm Mh

Si vous devez accéder à différentes clés imbriquées sans le savoir au moment du codage (il sera facile de les adresser), 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 par points 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 répond à votre question ...

MODIFIER

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

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 n'êtes pas à l'aise avec la méthode apply 

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ète les vérifie pour vous pour des erreurs de syntaxe et ainsi de suite.

À propos, j’estime qu’une simple mission faite au bon moment sera suffisante ...

0
Eineki

Je viens juste de poser la même question récemment et j'ai utilisé avec succès https://npmjs.org/package/tea-properties qui set également objet/tableau imbriqué:

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
abernier