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
majorBummer
la source
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.

loganfsmyth
la source
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})
}
Bergi
la source
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 };
Zfalen
la source
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

gafi
la source
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;
Matthias Günter
la source
C'est précisément ce que je voulais. Je vous remercie!
garrettmaring
let myTest = { test1, test3 } = myObject;ne fonctionne pas
Eatdoku
4

C'est tout à fait possible. Mais pas dans une seule déclaration.

var foo = {
    x: "bar",
    y: "baz"
};
var oof = {};
({x: oof.x, y: oof.y} = foo); // {x: "bar", y: "baz"}

(Notez la parenthèse autour de l'instruction.) Mais gardez à l'esprit que la lisibilité est plus importante que le code-golf :).

Source: http://exploringjs.com/es6/ch_destructuring.html#sec_assignment-targets

Hampus Ahlgren
la source
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)
CampSafari
la source
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));
Ben Copeland
la source
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})()});
utilisateur5733033
la source
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

RPichioli
la source
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"
}
user1577390
la source
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.

mpen
la source
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' }
Bart
la source
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.

Patrick Michaelsen
la source
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"}
Sornii
la source
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

Bharathvaj Ganesan
la source