Est-il possible de déstructurer sur un objet existant? (Javascript ES6)


136

Par exemple si j'ai deux objets:

var foo = {
  x: "bar",
  y: "baz"
}

et

var oof = {}

et je voulais transférer les valeurs x et y de foo à oof. Existe-t-il un moyen de le faire en utilisant la syntaxe de déstructuration es6?

peut-être quelque chose comme:

oof{x,y} = foo

10
Si vous souhaitez copier toutes les propriétésObject.assign(oof, foo)
elclanrs

Beaucoup d'exemples destructeurs ici sur MDN , mais je ne vois pas celui dont vous parlez.
jfriend00

Hmm, je n'ai pas pu en trouver un non plus ..
majorBummer

Voir ma réponse ci-dessous pour une solution à deux lignes sansObject.assign
Zfalen

Réponses:


116

Bien que moche et un peu répétitif, vous pouvez le faire

({x: oof.x, y: oof.y} = foo);

qui lira les deux valeurs de l' fooobjet, et les écrira à leurs emplacements respectifs sur l' oofobjet.

Personnellement, je préfère encore lire

oof.x = foo.x;
oof.y = foo.y;

ou

['x', 'y'].forEach(prop => oof[prop] = foo[prop]);

bien que.


2
L'alternative ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); comme je vois, est le seul DRY (ne vous répétez pas), jusqu'à présent. "DRY" serait en effet utile dans le cas de plusieurs clés à mapper. Vous n'auriez besoin de mettre à jour qu'un seul endroit. Peut-être que je me trompe. Merci quand même!
Vladimir Brasil

1
Le troisième exemple est DRY, mais vous devez utiliser des chaînes comme clés, ce que javascript fait normalement implicitement. Je ne suis pas convaincu que ce soit moins gênant que: const {x, y} = foo; const oof = {x, y};
Jeff Lowery

Quelqu'un peut-il me montrer dans jsfiddle où fonctionne la première suggestion? Cela ne fonctionne pas ici sur chrome: jsfiddle.net/7mh399ow
techguy2000

@ techguy2000 Vous avez oublié le point-virgule après var oof = {};.
loganfsmyth

Dans le premier code, ne devrait pas l'être ({x: oof.x, y: oof.y} = foo)? Je pense que vous avez mis un f supplémentaire dans oof .
Sornii

38

Non, la déstructuration ne prend pas en charge les expressions de membres en raccourcis, mais uniquement les noms de propriété simples pour le moment. Il y a eu des discussions à ce sujet sur esdiscuss, mais aucune proposition ne sera intégrée dans ES6.

Vous pourrez peut-être utiliser Object.assigncependant - si vous n'avez pas besoin de toutes vos propres propriétés, vous pouvez toujours le faire

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}

3
@loganfsmyth, votre exemple ne fonctionne pas pour moi au moins dans mes tests avec le nœud 4.2.2. avec --harmony_destructuringactivé. Je vois «SyntaxError: jeton inattendu».
jpierson

@loganfsmyth, vous devriez soumettre une réponse correcte car c'est un commentaire très utile imo.
Sulliwane

@Sulliwane: Il l'a fait (maintenant) . Bergi, serait probablement préférable de mettre à jour la réponse pour indiquer que vous pouvez utiliser des expressions de membre comme indiqué par Logan. (Est-il vraiment vrai que les spécifications ont autant changé entre avril et juin 2015?)
TJ Crowder

@TJCrowder Non, je ne pense pas que cela ait changé, je suppose que je parlais {oof.x, oof.y} = foo. Ou peut-être que je l'avais vraiment manqué.
Bergi

29

IMO, c'est le moyen le plus simple d'accomplir ce que vous recherchez:

let { prop1, prop2, prop3 } = someObject;
let data = { prop1, prop2, prop3 };

  // data === { prop1: someObject.prop1, ... }

Fondamentalement, déstructurez en variables, puis utilisez le raccourci d'initialisation pour créer un nouvel objet. Pas besoin dObject.assign

Je pense que c'est le moyen le plus lisible, de toute façon. Vous pouvez par la présente sélectionner les accessoires exacts someObjectque vous souhaitez. Si vous avez un objet existant dans lequel vous souhaitez simplement fusionner les accessoires, faites quelque chose comme ceci:

let { prop1, prop2, prop3 } = someObject;
let data = Object.assign(otherObject, { prop1, prop2, prop3 });
    // Makes a new copy, or...
Object.assign(otherObject, { prop1, prop2, prop3 });
    // Merges into otherObject

Une autre façon, sans doute plus propre, de l'écrire est:

let { prop1, prop2, prop3 } = someObject;
let newObject = { prop1, prop2, prop3 };

// Merges your selected props into otherObject
Object.assign(otherObject, newObject);

Je l'utilise POSTbeaucoup pour les demandes où je n'ai besoin que de quelques éléments de données discrètes. Mais, je suis d'accord qu'il devrait y avoir une seule ligne pour faire cela.

EDIT: PS - J'ai récemment appris que vous pouvez utiliser l'ultra déstructuration dans la première étape pour extraire des valeurs imbriquées d'objets complexes! Par exemple...

let { prop1, 
      prop2: { somethingDeeper }, 
      prop3: { 
         nested1: {
            nested2
         } 
      } = someObject;
let data = { prop1, somethingDeeper, nested2 };

De plus, vous pouvez utiliser l'opérateur de propagation au lieu d'Object.assign lors de la création d'un nouvel objet:

const { prop1, prop2, prop3 } = someObject;
let finalObject = {...otherObject, prop1, prop2, prop3 };

Ou...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };

J'aime cette approche, pragmatique.
Jesse

2
C'est ce que je fais mais ce n'est pas très sec. Je pense que ce dont beaucoup de gens ont vraiment besoin, c'est simplement d'une fonction d'extraction de touches.
jgmjgm

@jgmjgm ouais, ce serait bien d'en avoir un intégré mais je suppose que ce n'est pas trop difficile à écrire non plus.
Zfalen

12

Autre que Object.assign il y a la syntaxe de propagation d'objet qui est une proposition de l'étape 2 pour ECMAScript.

var foo = {
  x: "bar",
  y: "baz"
}

var oof = { z: "z" }

oof =  {...oof, ...foo }

console.log(oof)

/* result 
{
  "x": "bar",
  "y": "baz",
  "z": "z"
}
*/

Mais pour utiliser cette fonctionnalité, vous devez utiliser stage-2un transform-object-rest-spreadplugin pour babel. Voici une démo sur babel avecstage-2


9
Cela ne définit pas réellement les propriétés de l'objet existant, mais crée plutôt un nouvel objet contenant toutes les propriétés des deux.
Matt Browne

8

Plugin BabelJS

Si vous utilisez BabelJS, vous pouvez maintenant activer mon plugin babel-plugin-transform-object-from-destructuring( voir le package npm pour l'installation et l'utilisation ).

J'ai eu le même problème décrit dans ce fil et pour moi c'était très épuisant lorsque vous créez un objet à partir d'une expression de déstructuration, en particulier lorsque vous devez renommer, ajouter ou supprimer une propriété. Avec ce plugin, maintenir de tels scénarios devient beaucoup plus facile pour vous.

Exemple d'objet

let myObject = {
  test1: "stringTest1",
  test2: "stringTest2",
  test3: "stringTest3"
};
let { test1, test3 } = myObject,
  myTest = { test1, test3 };

peut s'écrire:

let myTest = { test1, test3 } = myObject;

Exemple de tableau

let myArray = ["stringTest1", "stringTest2", "stringTest3"];
let [ test1, , test3 ] = myArray,
  myTest = [ test1, test3 ];

peut s'écrire:

let myTest = [ test1, , test3 ] = myArray;

C'est précisément ce que je voulais. Je vous remercie!
garrettmaring

let myTest = { test1, test3 } = myObject;ne fonctionne pas
Eatdoku


3

Vous pouvez simplement utiliser la restructuration pour cela comme ceci:

const foo = {x:"a", y:"b"};
const {...oof} = foo; // {x:"a", y:"b"} 

Ou fusionnez les deux objets si oof a des valeurs:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)

Je pense que ce premier cas est exactement ce que je recherchais. Je l'ai essayé dans la console chrome et cela semble fonctionner. À votre santé! @campsafari
majorBummer

1
@majorBummer Votre appel à la fin, mais j'envisagerais une approche pour ne pas vraiment répondre à votre question, car ces deux éléments créent de nouveaux objets, plutôt que d'ajouter des propriétés aux objets existants comme votre titre le demande.
loganfsmyth

C'est un bon point @loganfsmyth. Je pense que j'étais juste excité par la méthode évoquée par campSafari parce que je n'avais pas réalisé que c'était possible.
majorBummer

1
Si cela ne vous dérange pas de créer un nouvel objet, vous pouvez simplement le faireoof = {...oof, ...foo}
Joshua Coady

2

Vous pouvez renvoyer l'objet déstructuré dans une fonction de flèche et utiliser Object.assign () pour l'affecter à une variable.

const foo = {
  x: "bar",
  y: "baz"
}

const oof = Object.assign({}, () => ({ x, y } = foo));

1

SEC

var a = {a1:1, a2: 2, a3: 3};
var b = {b1:1, b2: 2, b3: 3};

const newVar = (() => ({a1, a2, b1, b2})).bind({...a, ...b});
const val = newVar();
console.log({...val});
// print: Object { a1: 1, a2: 2, b1: 1, b2: 2 }

ou

console.log({...(() => ({a1, a2, b1, b2})).bind({...a, ...b})()});

1

Vous pouvez détruire un objet en l'affectant directement à un autre attribut d'objet.

Exemple de travail:

let user = {};
[user.name, user.username] = "Stack Overflow".split(' ');
document.write(`
1st attr: ${user.name} <br /> 
2nd attr: ${user.username}`);

Vous pouvez travailler avec la destruction en utilisant des variables avec le même nom d'attribut d'objet que vous voulez attraper, de cette façon vous n'avez pas besoin de faire:

let user = { name: 'Mike' }
let { name: name } = user;

Utilisez de cette façon:

let user = { name: 'Mike' }
let { name } = user;

De la même manière, vous pouvez définir de nouvelles valeurs pour les structures d'objets si elles ont le même nom d'attribut.

Regardez cet exemple de travail:

// The object to be destructed
let options = {
  title: "Menu",
  width: 100,
  height: 200
};

// Destructing
let {width: w, height: h, title} = options;

// Feedback
document.write(title + "<br />");  // Menu
document.write(w + "<br />");      // 100
document.write(h);                 // 200


0

Cela fonctionne dans Chrome 53.0.2785.89

let foo = {
  x: "bar",
  y: "baz"
};

let oof = {x, y} = foo;

console.log(`oof: ${JSON.stringify(oof)});

//prints
oof: {
  "x": "bar",
  "y": "baz"
}

7
Malheureusement, il semble oofsimplement recevoir une référence fooet contourner toute la déstructuration (au moins dans Chrome). oof === fooet let oof = { x } = fooretourne encore{ x, y }
Theo.T

@ Theo.T bonne prise. c'est dommage, je vais devoir trouver un autre moyen
user1577390

Ceux-ci valent la peine d'être gardés juste pour montrer à quel point JS peut être déroutant.
jgmjgm

0

J'ai trouvé cette méthode:

exports.pick = function pick(src, props, dest={}) {
    return Object.keys(props).reduce((d,p) => {
        if(typeof props[p] === 'string') {
            d[props[p]] = src[p];
        } else if(props[p]) {
            d[p] = src[p];
        }
        return d;
    },dest);
};

Que vous pouvez utiliser comme ceci:

let cbEvents = util.pick(this.props.events, {onFocus:1,onBlur:1,onCheck:'onChange'});
let wrapEvents = util.pick(this.props.events, {onMouseEnter:1,onMouseLeave:1});

c'est-à-dire que vous pouvez choisir les propriétés que vous voulez et les mettre dans un nouvel objet. contrairement à_.pick vous, vous pouvez également les renommer en même temps.

Si vous souhaitez copier les accessoires sur un objet existant, définissez simplement destarg.


0

C'est une sorte de triche, mais vous pouvez faire quelque chose comme ça ...

const originalObject = {
  hello: 'nurse',
  meaningOfLife: 42,
  your: 'mom',
};

const partialObject = (({ hello, your }) => {
  return { hello, your };
})(originalObject);

console.log(partialObject); // ​​​​​{ hello: 'nurse', your: 'mom' }​​​​​

En pratique, je pense que vous voudrez rarement l'utiliser. Ce qui suit est BEAUCOUP plus clair ... mais pas aussi amusant.

const partialObject = {
  hello: originalObject.hello,
  your: originalObject.your,
};

Un autre itinéraire complètement différent, qui comprend le déblayage avec le prototype (attention maintenant ...):

if (!Object.prototype.pluck) {
  Object.prototype.pluck = function(...props) {
    return props.reduce((destObj, prop) => {
      destObj[prop] = this[prop];

      return destObj;
    }, {});
  }
}

const originalObject = {
  hello: 'nurse',
  meaningOfLife: 42,
  your: 'mom',
};

const partialObject2 = originalObject.pluck('hello', 'your');

console.log(partialObject2); // { hello: 'nurse', your: 'mom' }

0

C'est la solution la plus lisible et la plus courte que je puisse proposer:

let props = { 
  isValidDate: 'yes',
  badProp: 'no!',
};

let { isValidDate } = props;
let newProps = { isValidDate };

console.log(newProps);

Il sortira { isValidDate: 'yes' }

Ce serait bien de pouvoir un jour dire quelque chose comme let newProps = ({ isValidDate } = props)mais malheureusement ce n'est pas quelque chose que ES6 prend en charge.


0

Ce n'est pas une belle façon, ni je le recommande, mais c'est possible de cette façon, juste pour la connaissance.

const myObject = {
  name: 'foo',
  surname: 'bar',
  year: 2018
};

const newObject = ['name', 'surname'].reduce(
  (prev, curr) => (prev[curr] = myObject[curr], prev),
  {},
);

console.log(JSON.stringify(newObject)); // {"name":"foo","surname":"bar"}

0

Vous pouvez utiliser des méthodes de classe JSON pour y parvenir comme suit

const foo = {
   x: "bar",
   y: "baz"
};

const oof = JSON.parse(JSON.stringify(foo, ['x','y']));
// output -> {x: "bar", y: "baz"}

Passez les propriétés qui doivent être ajoutées à l'objet résultant comme deuxième argument pour stringifyfonctionner dans un format de tableau.

MDN Doc pour JSON.stringify

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.