È possibile distruggere un oggetto esistente? (Javascript ES6)


136

Ad esempio se ho due oggetti:

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

e

var oof = {}

e volevo trasferire i valori xey da foo a oof. C'è un modo per farlo usando la sintassi destrutturante es6?

forse qualcosa del tipo:

oof{x,y} = foo

10
Se vuoi copiare tutte le proprietàObject.assign(oof, foo)
elclanrs

Molti esempi distruttivi qui su MDN , ma non vedo quello di cui stai chiedendo.
jfriend00

Hmm non sono riuscito a trovarne neanche uno ..
majorBummer,

Vedi la mia risposta qui sotto per una soluzione a due righe senzaObject.assign
Zfalen il

Risposte:


116

Mentre brutto e un po 'ripetitivo, puoi farlo

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

che leggerà i due valori foodell'oggetto e li scriverà nelle rispettive posizioni oofsull'oggetto.

Personalmente preferirei ancora leggere

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

o

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

anche se.


2
L'alternativa ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); come vedo, è l'unico SECCO (non ripeterti), fino ad ora. "DRY" sarebbe davvero utile nel caso di più tasti da mappare. Dovresti aggiornare solo un posto. Forse mi sbaglio. Grazie comunque!
Vladimir Brasil,

1
Il terzo esempio è DRY, ma devi usare le stringhe come chiavi, cosa che JavaScript normalmente fa implicitamente. Non convinto che sia meno fastidioso di: const {x, y} = pippo; const oof = {x, y};
Jeff Lowery,

Qualcuno può mostrarmi in jsfiddle dove funziona il primo suggerimento? Qui non funziona su Chrome: jsfiddle.net/7mh399ow
techguy2000

@ techguy2000 Dopo hai dimenticato il punto e virgola var oof = {};.
loganfsmyth,

Nel primo codice, non dovrebbe essere ({x: oof.x, y: oof.y} = foo)? Credo che tu abbia messo un extra f in oof .
Sornii,

38

No, la destrutturazione non supporta le espressioni dei membri in shorthands ma solo semplici nomi di proprietà al momento. Si è parlato di questo su esdiscuss, ma nessuna proposta entrerà in ES6.

Object.assignTuttavia, potresti essere in grado di utilizzare : se non hai bisogno di tutte le proprietà, puoi comunque farlo

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

3
@loganfsmyth, il tuo esempio non funziona per me almeno nei miei test con il nodo 4.2.2. con --harmony_destructuringabilitato. Vedo "SyntaxError: token imprevisto."
jpierson,

@loganfsmyth dovresti inviare una risposta adeguata in quanto questo è un commento molto utile imo.
Sulliwane,

@Sulliwane: l'ha fatto (ora) . Bergi, probabilmente sarebbe meglio aggiornare la risposta per chiamare che puoi usare le espressioni dei membri come mostrato da Logan. (È vero che le specifiche sono cambiate così tanto tra aprile e giugno 2015?)
TJ Crowder,

@TJCrowder No, non credo sia cambiato, credo di averne parlato {oof.x, oof.y} = foo. O forse mi ero davvero perso.
Bergi,

29

IMO questo è il modo più semplice per realizzare ciò che stai cercando:

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

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

Fondamentalmente, distruggere in variabili e quindi utilizzare la scorciatoia di inizializzazione per creare un nuovo oggetto. Non c'è bisogno diObject.assign

Penso che questo sia il modo più leggibile, comunque. Con la presente puoi selezionare i puntelli esatti tra someObjectquelli che desideri. Se hai un oggetto esistente in cui vuoi solo unire gli oggetti di scena, fai qualcosa del genere:

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

Un altro modo, probabilmente più pulito, per scriverlo è:

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

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

Lo uso molto per POSTrichieste in cui ho bisogno solo di alcuni dati discreti. Ma, sono d'accordo che ci dovrebbe essere un solo aspetto per farlo.

EDIT: PS - Recentemente ho imparato che puoi usare l'ultra destrutturazione nel primo passo per estrarre i valori nidificati da oggetti complessi! Per esempio...

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

Inoltre, è possibile utilizzare l'operatore spread anziché Object.assign quando si crea un nuovo oggetto:

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

O...

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

Mi piace questo approccio, pragmatico.
Jesse,

2
Questo è quello che faccio ma non è molto secco. Penso che molte persone abbiano davvero bisogno di una funzione di estrazione dei tasti.
jgmjgm,

@jgmjgm, sì, sarebbe bello averne uno integrato, ma credo che non sia neanche troppo difficile da scrivere.
Zfalen,

12

Oltre a ciò Object.assignc'è la sintassi di diffusione dell'oggetto che è una proposta Stage 2 per ECMAScript.

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

var oof = { z: "z" }

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

console.log(oof)

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

Ma per usare questa funzione devi usare stage-2o transform-object-rest-spreadplugin per babel. Ecco una demo di Babel constage-2


9
Questo in realtà non imposta le proprietà sull'oggetto esistente, ma crea piuttosto un nuovo oggetto contenente tutte le proprietà di entrambi.
Matt Browne,

8

Plugin BabelJS

Se stai usando BabelJS ora puoi attivare il mio plugin babel-plugin-transform-object-from-destructuring( vedi pacchetto npm per l'installazione e l'uso ).

Ho avuto lo stesso problema descritto in questo thread e per me è stato molto estenuante quando si crea un oggetto da un'espressione destrutturante, soprattutto quando è necessario rinominare, aggiungere o rimuovere una proprietà. Con questo plugin mantenere tali scenari diventa molto più facile per te.

Esempio di oggetto

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

può essere scritto come:

let myTest = { test1, test3 } = myObject;

Esempio di array

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

può essere scritto come:

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

Questo è esattamente quello che volevo. Grazie!
Garrettmaring,

let myTest = { test1, test3 } = myObject;non funziona
Eatdoku,


3

Puoi semplicemente usare la ristrutturazione per questo in questo modo:

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

O unisci entrambi gli oggetti se oof ha valori:

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

Penso che questo primo caso sia esattamente quello che stavo cercando. L'ho provato nella console di Chrome e sembra funzionare. Saluti! @campsafari
majorBummer,

1
@majorBummer Alla fine la tua chiamata, ma prenderei in considerazione l'approccio per non rispondere effettivamente alla tua domanda, perché entrambi creano nuovi oggetti, piuttosto che aggiungere proprietà agli oggetti esistenti come il tuo titolo chiede.
loganfsmyth,

Questo è un buon punto @loganfsmyth. Penso di essere stato solo eccitato dal metodo campSafari cresciuto perché non mi ero reso conto che fosse possibile.
majorBummer,

1
Se non ti dispiace creare un nuovo oggetto, potresti semplicemente fareoof = {...oof, ...foo}
Joshua Coady,

2

È possibile restituire l'oggetto destrutturato in una funzione freccia e utilizzare Object.assign () per assegnarlo a una variabile.

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

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

1

ASCIUTTO

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 }

o

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

1

È possibile distruggere un oggetto assegnando direttamente a un altro attributo oggetto.

Esempio funzionante:

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

Puoi lavorare con la distruzione usando le variabili con lo stesso nome dell'attributo oggetto che vuoi catturare, in questo modo non devi fare:

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

Usa in questo modo:

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

Allo stesso modo è possibile impostare nuovi valori per le strutture degli oggetti se hanno lo stesso nome di attributo.

Guarda questo esempio funzionante:

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

Funziona in 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
Purtroppo sembra oofsolo ricevere un riferimento fooe eludere l'intera destrutturazione (almeno in Chrome). oof === fooe let oof = { x } = footuttavia restituisce{ x, y }
Theo.T

@ Theo.T buona cattura. è un peccato, dovrò trovare un altro modo
user1577390

Vale la pena mantenerli solo per dimostrare come JS possa creare confusione.
jgmjgm,

0

Ho escogitato questo metodo:

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);
};

Che puoi usare in questo modo:

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

cioè, puoi scegliere quali proprietà vuoi estrarre e inserirle in un nuovo oggetto. diversamente da_.pick di puoi anche rinominarli contemporaneamente.

Se vuoi copiare gli oggetti di scena su un oggetto esistente, basta impostare l' destarg.


0

Questo è un po 'barare, ma puoi fare qualcosa del genere ...

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

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

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

In pratica, penso che raramente vorresti usarlo. Quanto segue è MOLTO più chiaro ... ma non altrettanto divertente.

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

Un altro percorso completamente diverso, che include il mucking con il prototipo (attenzione ora ...):

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

Questa è la soluzione più leggibile e più breve che potrei trovare:

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

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

console.log(newProps);

Verrà emesso { isValidDate: 'yes' }

Sarebbe bello poter un giorno dire qualcosa del genere, let newProps = ({ isValidDate } = props)ma sfortunatamente non è qualcosa che ES6 supporta.


0

Non è un modo bellissimo, né lo consiglio, ma è possibile in questo modo, solo per conoscenza.

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

È possibile utilizzare i metodi della classe JSON per ottenerlo come segue

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

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

Passare le proprietà che devono essere aggiunte all'oggetto risultante come secondo argomento per stringifyfunzionare in un formato array.

MDN Doc per JSON.stringify

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.