3
votes

Javascript: modification d'un objet imbriqué dans le raccourci ES6

Considérons qu'une fonction renvoie un objet imbriqué et je veux modifier la propriété à l'intérieur de l'objet imbriqué.

Dans l'exemple ci-dessous, j'appelle la fonction plusieurs fois ou je dois la stocker dans une variable temporaire. Existe-t-il un moyen d'appeler une seule fois à l'intérieur des accolades et de diffuser / modifier plusieurs fois à l'intérieur du même objet.

const getObject = () => {
   return {
     a: {
      b: {
        c: 1,
        d: 2,
      }
     },
     e: 3
   }
}

var modifiedD = {
  ...getObject(),
  a: {
     b: {
      ...getObject().a.b,
      d: 4
     }
  }
}

console.log(modifiedD);


2 commentaires

Vous pouvez créer une fonction d'usine pour cela en utilisant simplement le résultat de getObject () dans sa plage lexicale. Ou vous pouvez utiliser lodash et sa méthode set puisque vous avez exactement ce que vous voulez changer. lodash.com/docs/4.17.11#set


const initialvalue = getObject ();


3 Réponses :


4
votes

lors de la déclaration de une clé après ... getObject () , il remplace la valeur entière. Il ne fusionne pas l'objet interne derrière a .

Vous pouvez donc le faire comme vous l'avez fait et appeler getObject () plusieurs fois.


Une autre solution pourrait être de le gérer en utilisant une fonction de votre propre fusion des objets, comme:

const getObject = () => {
   return {
     a: {
      b: {
        c: 1,
        d: 2,
      }
     },
     e: 3
   }
}

const modifiedD = getObject();

modifiedD.a.b.d = 4;

console.log(modifiedD);

ATTENTION, la fonction que j'ai faite muter l'objet qui n'est peut-être pas la meilleure réponse


Ou appelez-la une seule fois puis définissez le clés une par une comme:

function mergeObjects(obj1, obj2) {
  // We are going to copy the value of each obj2 key into obj1
  Object.keys(obj2).forEach((x) => {
    // If we have an object, we go deeper
    if (typeof obj2[x] === 'object') {
      if (obj1[x] === void 0) {
        obj1[x] = {};
      }

      mergeObjects(obj1[x], obj2[x]);
    } else {
      obj1[x] = obj2[x];
    }
  });
  
  return obj1;
}

const getObject = () => {
  return {
    a: {
      b: {
        c: 1,
        d: 2,
      }
    },
    e: 3
  }
}

const modifiedD = mergeObjects(getObject(), {
  a: {
    b: {
      d: 4,
    },
  },
});

console.log(modifiedD);


0 commentaires

-1
votes

Vous pouvez essayer ce qui suit:

getParentObj(path, obj) {
   return path.split('.').reduce((o,i)=>o[i], obj);
}

const parent = getParentObj('a.b', getObject());
parent[d] = 24;


0 commentaires

0
votes

Suite à ma réponse précédente, comme l'a souligné Grégory NEUT, vous pourriez avoir une complexité beaucoup plus grande.

Si c'est le cas, vous pouvez simplement créer deux objets et les fusionner. J'ai trouvé un extrait de code de fonction pour pouvoir le faire en utilisant Object.assign

Exemple:

const getObject = () => {
   return {
     a: {
      b: {
        c: 1,
        d: 2,
      }
     },
     e: 3
   }
}

var modifiedD = getObject();
var newD = {
  a: {
     b: {
       d: 4
     },
     y: 1
  },
  z: 20
}

/** TAKEN FROM https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6 **/
// Merge a `source` object to a `target` recursively
const merge = (target, source) => {
  // Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties
  for (let key of Object.keys(source)) {
    if (source[key] instanceof Object) Object.assign(source[key], merge(target[key], source[key]))
  }

  // Join `target` and modified `source`
  Object.assign(target || {}, source)
  return target
}

modifiedD = merge(modifiedD, newD);

console.log(modifiedD);


0 commentaires