Ist es möglich, ein vorhandenes Objekt zu zerstören? (Javascript ES6)

135

Zum Beispiel, wenn ich zwei Objekte habe:

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

und

var oof = {}

und ich wollte die x- und y-Werte von foo nach oof übertragen. Gibt es eine Möglichkeit, dies mithilfe der es6-Destrukturierungssyntax zu tun?

vielleicht so etwas wie:

oof{x,y} = foo
majorBummer
quelle
10
Wenn Sie alle Eigenschaften kopieren möchtenObject.assign(oof, foo)
elclanrs
Viele zerstörerische Beispiele hier auf MDN , aber ich sehe nicht das, nach dem Sie fragen.
jfriend00
Hmm, ich konnte auch keinen finden ..
majorBummer
Siehe meine Antwort unten für eine zweizeilige Lösung ohneObject.assign
Zfalen

Antworten:

115

Während hässlich und ein bisschen repetitiv, können Sie tun

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

Dadurch werden die beiden Werte des fooObjekts gelesen und an ihre jeweiligen Positionen auf dem oofObjekt geschrieben.

Persönlich würde ich immer noch lieber lesen

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

oder

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

obwohl.

loganfsmyth
quelle
2
Die Alternative ['x', 'y']. ForEach (prop => oof [prop] = foo [prop]); Wie ich sehe, ist der einzige DRY (wiederholen Sie sich nicht), bis jetzt. "DRY" wäre in der Tat nützlich, wenn mehrere Schlüssel zugeordnet werden sollen. Sie müssten nur einen Ort aktualisieren. Vielleicht irre ich mich. Danke trotzdem!
Vladimir Brasil
1
Das dritte Beispiel ist DRY, aber Sie müssen Zeichenfolgen als Schlüssel verwenden, was Javascript normalerweise implizit tut. Nicht überzeugt, dass dies weniger störend ist als: const {x, y} = foo; const oof = {x, y};
Jeff Lowery
Kann mir jemand in jsfiddle zeigen, wo der erste Vorschlag funktioniert? Es funktioniert hier nicht auf Chrome: jsfiddle.net/7mh399ow
techguy2000
@ techguy2000 Du hast das Semikolon danach vergessen var oof = {};.
Loganfsmyth
Sollte im ersten Code nicht sein ({x: oof.x, y: oof.y} = foo)? Ich denke, Sie haben ein zusätzliches f in oof gesetzt .
Sornii
38

Nein, die Destrukturierung unterstützt derzeit keine Mitgliedsausdrücke in Kurzform, sondern nur einfache Eigenschaftsnamen. Es gab Gespräche darüber auf esdiscuss, aber keine Vorschläge werden es in ES6 schaffen.

Möglicherweise können Sie Object.assignjedoch verwenden - wenn Sie nicht alle eigenen Eigenschaften benötigen, können Sie dies dennoch tun

var foo = …,
    oof = {};
{
    let {x, y} = foo;
    Object.assign(oof, {x, y})
}
Bergi
quelle
3
@loganfsmyth, Ihr Beispiel funktioniert zumindest in meinen Tests mit Knoten 4.2.2 nicht für mich. mit --harmony_destructuringaktiviert. Ich sehe "SyntaxError: Unerwartetes Token".
Jpierson
@loganfsmyth Sie sollten eine richtige Antwort einreichen, da dies ein sehr nützlicher Kommentar imo ist.
Sulliwane
@Sulliwane: Er hat es (jetzt) ​​getan . Bergi, wäre wahrscheinlich am besten, um die Antwort zu aktualisieren , zu rufen , dass Sie können Mitglied Ausdrücke verwenden , wie von Logan gezeigt. (Stimmt es wirklich, dass sich die Spezifikation zwischen April und Juni 2015 so stark geändert hat?)
TJ Crowder
@TJCrowder Nein, ich glaube nicht, dass es sich geändert hat, ich denke, ich habe darüber gesprochen {oof.x, oof.y} = foo. Oder vielleicht hatte ich es wirklich vermisst.
Bergi
29

IMO ist dies der einfachste Weg, um das zu erreichen, wonach Sie suchen:

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

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

Grundsätzlich in Strukturen zerlegen und dann die Initialisierungskürzel verwenden, um ein neues Objekt zu erstellen. Kein Bedarf fürObject.assign

Ich denke, das ist sowieso der am besten lesbare Weg. Hiermit können Sie genau die Requisiten auswählen, die someObjectSie möchten. Wenn Sie ein vorhandenes Objekt haben, in das Sie nur die Requisiten zusammenführen möchten, gehen Sie wie folgt vor:

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

Eine andere, wohl sauberere Art, es zu schreiben, ist:

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

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

Ich benutze dies häufig für POSTAnfragen, bei denen ich nur wenige diskrete Daten benötige. Aber ich stimme zu, dass es dafür einen Einzeiler geben sollte.

EDIT: PS - Ich habe kürzlich erfahren, dass Sie im ersten Schritt Ultra-Destrukturierung verwenden können, um verschachtelte Werte aus komplexen Objekten herauszuholen! Zum Beispiel...

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

Außerdem können Sie beim Erstellen eines neuen Objekts den Spread-Operator anstelle von Object.assign verwenden:

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

Oder...

const { prop1, prop2, prop3 } = someObject;
const intermediateObject = { prop1, prop2, prop3 };
const finalObject = {...otherObject, ...intermediateObject };
Zfalen
quelle
Ich mag diesen Ansatz, pragmatisch.
Jesse
2
Das mache ich, aber es ist nicht sehr trocken. Ich denke, was viele Leute wirklich brauchen, ist nur eine Funktion zum Extrahieren von Tasten.
jgmjgm
@jgmjgm Ja, es wäre schön, wenn einer eingebaut wäre, aber ich denke, das ist auch nicht allzu schwer zu schreiben.
Zfalen
12

Abgesehen von Object.assignder Objektverbreitungssyntax handelt es sich um einen Stage 2-Vorschlag für ECMAScript.

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

var oof = { z: "z" }

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

console.log(oof)

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

Um diese Funktion nutzen zu können, müssen Sie jedoch babel verwenden stage-2oder ein transform-object-rest-spreadPlugin verwenden. Hier ist eine Demo zu Babel mitstage-2

Gafi
quelle
9
Dadurch werden die Eigenschaften des vorhandenen Objekts nicht festgelegt, sondern es wird ein neues Objekt erstellt, das alle Eigenschaften beider Objekte enthält.
Matt Browne
8

BabelJS Plugin

Wenn Sie BabelJS verwenden , können Sie jetzt mein Plugin aktivieren babel-plugin-transform-object-from-destructuring( Installation und Verwendung finden Sie im npm-Paket ).

Ich hatte das gleiche Problem, das in diesem Thread beschrieben wurde, und für mich war es sehr anstrengend, wenn Sie ein Objekt aus einem destrukturierenden Ausdruck erstellen, insbesondere wenn Sie eine Eigenschaft umbenennen, hinzufügen oder entfernen müssen. Mit diesem Plugin wird das Verwalten solcher Szenarien für Sie viel einfacher.

Objektbeispiel

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

kann geschrieben werden als:

let myTest = { test1, test3 } = myObject;

Array-Beispiel

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

kann geschrieben werden als:

let myTest = [ test1, , test3 ] = myArray;
Matthias Günter
quelle
Genau das wollte ich. Danke dir!
Garrettmaring
4

Es ist absolut möglich. Nur nicht in einer Aussage.

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

(Beachten Sie die Klammern um die Aussage.) Beachten Sie jedoch, dass Lesbarkeit wichtiger ist als Code-Golf :).

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

Hampus Ahlgren
quelle
3

Sie können die Umstrukturierung einfach so verwenden:

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

Oder führen Sie beide Objekte zusammen, wenn oof Werte hat:

const foo = {x:"a", y:"b"};
let oof = {z:"c"}
oof = Object.assign({}, oof, foo)
CampSafari
quelle
Ich denke, dieser erste Fall ist genau das, wonach ich gesucht habe. Ich habe es in der Chromkonsole ausprobiert und es scheint zu funktionieren. Prost! @campsafari
majorBummer
1
@majorBummer Ihr Anruf am Ende, aber ich würde in Betracht ziehen, Ihre Frage nicht wirklich zu beantworten, da beide neue Objekte erstellen , anstatt vorhandenen Objekten Eigenschaften hinzuzufügen, wie es Ihr Titel verlangt.
Loganfsmyth
Das ist ein guter Punkt @loganfsmyth. Ich glaube, ich war nur begeistert von der Methode, die campSafari angesprochen hat, weil ich nicht bemerkt hatte, dass das möglich ist.
MajorBummer
1
Wenn es Ihnen nichts ausmacht, ein neues Objekt zu erstellen, können Sie es einfach tunoof = {...oof, ...foo}
Joshua Coady
2

Sie können das zerstörte Objekt in einer Pfeilfunktion zurückgeben und es mit Object.assign () einer Variablen zuweisen.

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

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

TROCKEN

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 }

oder

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

Sie können ein Objekt zerstören, das direkt einem anderen Objektattribut zugewiesen ist.

Arbeitsbeispiel:

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

Sie können mit der Zerstörung arbeiten, indem Sie Variablen mit demselben Namen des Objektattributs verwenden, das Sie abfangen möchten. Auf diese Weise müssen Sie Folgendes nicht tun:

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

Verwenden Sie diesen Weg:

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

Auf die gleiche Weise können Sie neue Werte für Objektstrukturen festlegen, wenn diese denselben Attributnamen haben.

Schauen Sie sich dieses Arbeitsbeispiel an:

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

Dies funktioniert in Chrom 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
quelle
7
Leider scheint es so, als würde man oofnur eine Referenz erhalten foound die gesamte Destrukturierung umgehen (zumindest in Chrome). oof === foound let oof = { x } = fookehrt doch zurück{ x, y }
Theo.T
@ Theo.T guter Fang. Das ist ein Mist, ich muss einen anderen Weg finden
user1577390
Diese sind es wert, aufbewahrt zu werden, um zu demonstrieren, wie verwirrend JS sein kann.
jgmjgm
0

Ich habe mir diese Methode ausgedacht:

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

Was Sie so verwenden können:

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

Sie können also auswählen, welche Eigenschaften Sie ausgeben möchten, und sie in ein neues Objekt einfügen. Im Gegensatz _.pickdazu können Sie sie auch gleichzeitig umbenennen.

Wenn Sie die Requisiten auf ein vorhandenes Objekt kopieren möchten, setzen Sie einfach das destArgument.

mpen
quelle
0

Das ist eine Art Betrug, aber Sie können so etwas tun ...

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

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

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

In der Praxis würde man das allerdings selten nutzen wollen. Das Folgende ist VIEL klarer ... aber bei weitem nicht so lustig.

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

Eine andere völlig andere Route, die das Mucken mit dem Prototyp beinhaltet (jetzt vorsichtig ...):

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
quelle
0

Dies ist die am besten lesbare und kürzeste Lösung, die ich finden konnte:

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

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

console.log(newProps);

Es wird ausgegeben { isValidDate: 'yes' }

Es wäre schön, eines Tages so etwas sagen zu können, let newProps = ({ isValidDate } = props)aber leider wird es von ES6 nicht unterstützt.

Patrick Michaelsen
quelle
0

Es ist kein schöner Weg, noch empfehle ich ihn, aber es ist auf diese Weise möglich, nur für Wissen.

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
quelle
0

Sie können JSON-Klassenmethoden verwenden, um dies wie folgt zu erreichen

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

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

Übergeben Sie Eigenschaften, die dem resultierenden Objekt als zweites Argument hinzugefügt werden müssen, um stringifyin einem Array-Format zu funktionieren.

MDN-Dokument für JSON.stringify

Bharathvaj Ganesan
quelle