145 votes

Définir dynamiquement la propriété d'un objet imbriqué

J'ai un objet qui pourrait être de n'importe quel niveau de profondeur et pourrait avoir n'importe quelles propriétés existantes. Par exemple:

var obj = {
    db: {
        mongodb: {
            host: 'localhost'
        }
    }
};

Sur cela, j'aimerais définir (ou écraser) des propriétés de cette manière:

set('db.mongodb.user', 'root');
// ou:
set('foo.bar', 'baz');

Où la chaîne de propriété peut avoir n'importe quelle profondeur, et la valeur peut être de n'importe quel type/chose.
Les objets et les tableaux en tant que valeurs n'ont pas besoin d'être fusionnés, si la clé de propriété existe déjà.

L'exemple précédent produirait l'objet suivant:

var obj = {
    db: {
        mongodb: {
            host: 'localhost',
            user: 'root'
        }
    },
    foo: {
        bar: baz
    }
};

Comment puis-je réaliser une telle fonction?

0voto

Yamcha Points 548

JQuery dispose d'une méthode extend :

https://api.jquery.com/jquery.extend/

il suffit de passer les écrasements en tant qu'objet et il fusionnera les deux.

0voto

Lucas Leblow Points 23

Inspiré par assoc-in de ClojureScript (https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L5280), en utilisant la récursion :

/**
 * Associer une valeur (v) dans un objet/tableau (m) à une clé/index (k).
 * Si m est faux, utilisez un nouvel objet.
 * Renvoie l'objet/tableau mis à jour.
 */
function assoc(m, k, v) {
    m = (m || {});
    m[k] = v;
    return m;
}

/**
 * Associer une valeur (v) dans un objet/tableau imbriqué (m) en utilisant une séquence de clés (ks)
 * pour identifier le chemin vers la clé/index imbriqué.
 * Si l'une des valeurs dans l'objet/tableau imbriqué n'existe pas, elle ajoute
 * un nouvel objet.
 */
function assoc_in(m={}, [k, ...ks], v) {
    return ks.length ? assoc(m, k, assoc_in(m[k], ks, v)) : assoc(m, k, v);
}

/**
 * Associer une valeur (v) dans un objet/tableau imbriqué (m) en utilisant la notation de chaîne de clés (s)
 * (par exemple. "k1.k2").
 */
function set(m, s, v) {
    ks = s.split(".");
    return assoc_in(m, ks, v);
}

Note :

Avec l'implémentation fournie,

assoc_in({"a": 1}, ["a", "b"], 2) 

retourne

{"a": 1}

Je préférerais qu'une erreur soit renvoyée dans ce cas. Si désiré, vous pouvez ajouter une vérification dans assoc pour vérifier que m est soit un objet soit un tableau et renvoyer une erreur sinon.

0voto

Arun Kumar Saini Points 275

J'ai essayé d'écrire cette méthode de définition en bref, cela pourrait aider quelqu'un!

function set(obj, key, value) {
 let keys = key.split('.');
 if(keys.length<2){ obj[key] = value; return obj; }

 let lastKey = keys.pop();

 let fun = `obj.${keys.join('.')} = {${lastKey}: '${value}'};`;
 return new Function(fun)();
}

var obj = {
"hello": {
    "world": "test"
}
};

set(obj, "hello.world", 'test updated'); 
console.log(obj);

set(obj, "hello.world.again", 'hello again'); 
console.log(obj);

set(obj, "hello.world.again.onece_again", 'hello once again');
console.log(obj);

0voto

const set = (o, chemin, valeur) => {
    const props = chemin.split('.');
    const prop = props.shift()
    if (props.length === 0) {
        o[prop] = valeur
    } else {
        o[prop] = o[prop] ?? {}
        set(o[prop], props.join('.'), valeur)
    }
}

0voto

Vivek sharma Points 19

Si vous souhaitez mettre à jour ou insérer profondément un objet, essayez ceci :-

 let init = {
       abc: {
           c: {1: 2, 3: 5, 0: {l: 3}},
           d: 100
       }
    }
    Object.prototype.deepUpdate = function(update){
       let key = Object.keys(update);
       key.forEach((k) => {
           if(typeof update[key] == "object"){
              this[k].deepUpdate(update[key], this[k])
           }
           else 
           this[k] = update[k]
       })
    }

    init.deepUpdate({abc: {c: {l: 10}}})
    console.log(init)

mais assurez-vous qu'il change l'objet original, vous pouvez le faire pour ne pas changer l'objet original :

JSON.parse(JSON.stringify(init)).deepUpdate({abc: {c: {l: 10}}})

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X