it-swarm.com.de

Object spread vs. Object.assign

Angenommen, ich habe eine options -Variable und möchte einen Standardwert festlegen.

Was ist der Vorteil/Nachteil dieser beiden Alternativen?

Objektverbreitung verwenden

options = {...optionsDefault, ...options};

Oder mit Object.assign

options = Object.assign({}, optionsDefault, options);

Dies ist das Festschreiben , das mich wundern ließ.

317

Dies ist nicht unbedingt vollständig.

Spread-Syntax

options = {...optionsDefault, ...options};

Vorteile:

  • Wenn Sie Code für die Ausführung in Umgebungen ohne native Unterstützung verfassen, können Sie diese Syntax möglicherweise einfach kompilieren (im Gegensatz zur Verwendung einer Polyfill). (Zum Beispiel mit Babel.)

  • Weniger ausführlich.

Nachteile:

  • Als diese Antwort ursprünglich geschrieben wurde, war dies ein Vorschlag , nicht standardisiert. Überlegen Sie bei der Verwendung von Vorschlägen, was Sie tun würden, wenn Sie jetzt Code damit schreiben und dieser nicht standardisiert wird oder sich auf dem Weg zur Standardisierung ändert. Dies wurde seitdem in ES2018 standardisiert.

  • Wörtlich, nicht dynamisch.


Object.assign()

options = Object.assign({}, optionsDefault, options);

Vorteile:

  • Standardisiert.

  • Dynamisch. Beispiel:

    var sources = [{a: "A"}, {b: "B"}, {c: "C"}];
    options = Object.assign.apply(Object, [{}].concat(sources));
    // or
    options = Object.assign({}, ...sources);
    

Nachteile:

  • Ausführlicher.
  • Wenn Sie Code für die Ausführung in Umgebungen ohne native Unterstützung verfassen, müssen Sie Polyfill ausführen.

Dies ist die Verpflichtung, die mich wundern ließ.

Das hängt nicht direkt mit dem zusammen, was Sie fragen. Dieser Code verwendete nicht Object.assign(), sondern den Benutzercode (object-assign), der dasselbe tut. Offenbar kompilieren sie diesen Code mit Babel (und bündeln ihn mit Webpack), worüber ich gesprochen habe: Die Syntax, die Sie einfach kompilieren können. Sie zogen es anscheinend vor, object-assign als Abhängigkeit einschließen zu müssen, die in ihren Build einfließen würde.

282
JMM

Als Referenzobjekt wird Rest/Spread in ECMAScript 2018 als Stufe 4 finalisiert. Der Vorschlag ist zu finden hier .

Zum größten Teil funktionieren das Zurücksetzen und Verteilen von Objekten auf dieselbe Weise. Der Hauptunterschied besteht darin, dass spread Eigenschaften definiert, während Object.assign () sie festlegt . Dies bedeutet, dass Object.assign () Setter auslöst.

Ansonsten wird object rest/spread 1: 1 auf Object.assign () abgebildet und verhält sich anders als array (iterable) spread. Beispielsweise werden beim Verteilen eines Arrays Nullwerte verteilt. Bei der Verwendung von NULL-Werten mit Objektverbreitung werden diese jedoch unbemerkt weitergegeben.

Array (Iterable) Spread Beispiel

const x = [1, 2, null , 3];
const y = [...x, 4, 5];

console.log(y); // [1, 2, null, 3, 4, 5];

Objektverbreitungsbeispiel

const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};

console.log(z); //{a: 1, b: 2}

Dies steht im Einklang mit der Funktionsweise von Object.assign (). Beide schließen den Nullwert ohne Fehler unbemerkt aus.

const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);

console.log(z); //{a: 1, b: 2}
138
tomhughes

Ich denke, ein großer Unterschied zwischen dem Spread-Operator und Object.assign, der in den aktuellen Antworten nicht erwähnt zu werden scheint, ist, dass der Spread-Operator den Prototyp nicht intakt hält. Wenn Sie einem Objekt Eigenschaften hinzufügen und nicht ändern möchten, wovon es eine Instanz ist, müssen Sie Object.assign verwenden. Das folgende Beispiel soll dies demonstrieren:

const error = new Error();
error instanceof Error // true

const errorExtendedUsingSpread = {
  ...error,
  ...{
    someValue: true
  }
};
errorExtendedUsingSpread instanceof Error; // false

const errorExtendedUsingAssign = Object.assign(error, {
  someValue: true
});
errorExtendedUsingAssign instanceof Error; // true
20
Sean Dawson

Der Objektverbreitungsoperator (...) funktioniert in Browsern nicht, da er noch nicht Teil einer ES-Spezifikation ist, sondern nur ein Vorschlag. Die einzige Möglichkeit ist, es mit Babel (oder etwas ähnlichem) zu kompilieren.

Wie Sie sehen, ist es nur syntaktischer Zucker über Object.assign ({}).

Soweit ich sehen kann, sind dies die wesentlichen Unterschiede.

  • Object.assign funktioniert in den meisten Browsern (ohne zu kompilieren)
  • ... für Objekte ist nicht standardisiert
  • ... schützt Sie vor versehentlichem Mutieren des Objekts
  • ... füllt Object.assign in Browsern ohne dieses poly
  • ... benötigt weniger Code, um dieselbe Idee auszudrücken
12
Karthick Kumar

Wie bereits erwähnt, erfordert Object.assign() zum jetzigen Zeitpunkt eine Polyfüllung und die Objektverteilung ... eine Transpilation (und möglicherweise auch eine Polyfüllung), um zu funktionieren.

Betrachten Sie diesen Code:

// Babel wont touch this really, it will simply fail if Object.assign() is not supported in browser.
const objAss = { message: 'Hello you!' };
const newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);

// Babel will transpile with use to a helper function that first attempts to use Object.assign() and then falls back.
const objSpread = { message: 'Hello you!' };
const newObjSpread = {...objSpread, dev: true };
console.log(newObjSpread);

Diese beiden erzeugen die gleiche Ausgabe.

Hier ist die Ausgabe von Babel an ES5:

var objAss = { message: 'Hello you!' };
var newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var objSpread = { message: 'Hello you!' };
var newObjSpread = _extends({}, objSpread, { dev: true });
console.log(newObjSpread);

Dies ist soweit mein Verständnis. Object.assign() ist eigentlich standardisiert, wobei als Objekt Spread ... noch nicht existiert. Das einzige Problem ist die Browserunterstützung für das erstere und in Zukunft auch für das letztere.

Hier mit dem Code spielen

Hoffe das hilft.

12

Ich möchte den Status der ES-Funktion "Spread Object Merge" in Browsern und im Ökosystem über Tools zusammenfassen.

Spec

Browser: in Chrome, in SF, in Kürze Firefox (Version 60, IIUC)

  • Browser-Unterstützung für "Spread-Eigenschaften" in Chrome 60 , einschließlich dieses Szenarios.
  • Die Unterstützung für dieses Szenario funktioniert im aktuellen Firefox (59) NICHT, funktioniert jedoch in meiner Firefox Developer Edition. Ich glaube, es wird in Firefox 60 ausgeliefert.
  • Safari: nicht getestet, aber Kangax sagt, dass es in Desktop Safari 11.1 funktioniert, jedoch nicht in SF 11
  • iOS Safari: nicht abgeschlossen, aber Kangax sagt, dass es in iOS 11.3 funktioniert, aber nicht in iOS 11
  • noch nicht in Edge

Tools: Node 8.7, TS 2.1

Links

Codebeispiel (Doppelt als Kompatibilitätstest)

var x = { a: 1, b: 2 };
var y = { c: 3, d: 4, a: 5 };
var z = {...x, ...y};
console.log(z); // { a: 5, b: 2, c: 3, d: 4 }

Nochmals: Zum Zeitpunkt des Schreibens funktioniert dieses Beispiel ohne Transpilation in Chrome (60+), Firefox Developer Edition (Vorschau von Firefox 60) und Node (8.7+).

Warum antworten?

Ich schreibe diese 2,5 Jahre nach der ursprünglichen Frage. Aber ich hatte genau die gleiche Frage, und hier hat Google mich hingeschickt. Ich bin ein Sklave von SOs Mission, den langen Schwanz zu verbessern.

Da dies eine Erweiterung der "Array Spread" -Syntax ist, fiel es mir sehr schwer, Google zu verwenden und in Kompatibilitätstabellen nur schwer zu finden. Der nächstgelegene, den ich finden konnte, ist Kangax "property spread" , aber dieser Test enthält nicht zwei Spreads im selben Ausdruck (keine Zusammenführung). Auch der Name in den Vorschlägen/Entwürfen/Browser-Statusseiten verwendet alle "Eigenschaftsverbreitung", aber es scheint mir, dass dies ein "erster Prinzipal" war, zu dem die Community nach den Vorschlägen zur Verwendung der Verbreitungssyntax für "Objektzusammenführung" gelangt ist. (Dies könnte erklären, warum es so schwierig ist, zu googeln.) Ich dokumentiere meine Ergebnisse hier, damit andere Personen Links zu dieser bestimmten Funktion anzeigen, aktualisieren und kompilieren können. Ich hoffe es fängt an. Bitte helfen Sie dabei, die Nachricht darüber zu verbreiten, dass sie in der Spezifikation und in Browsern landet.

Zuletzt hätte ich diese Informationen als Kommentar hinzugefügt, aber ich konnte sie nicht bearbeiten, ohne die ursprüngliche Absicht der Autoren zu brechen. Insbesondere kann ich den Kommentar von @ ChillyPenguin nicht bearbeiten, ohne seine Absicht zu verlieren, @RichardSchulte zu korrigieren. Jahre später stellte sich heraus, dass Richard Recht hatte (meiner Meinung nach). Also schreibe ich stattdessen diese Antwort, in der Hoffnung, dass sie irgendwann die alten Antworten aufgreift (es könnte Jahre dauern, aber darum geht es schließlich beim Long Tail Effekt).

11
yzorg

HINWEIS: Spread ist NICHT nur syntaktischer Zucker um Object.assign. Sie arbeiten hinter den Kulissen sehr unterschiedlich.

Object.assign wendet Setter auf ein neues Objekt an, Spread nicht. Darüber hinaus muss das Objekt iterierbar sein.

Kopieren Verwenden Sie diese Option, wenn Sie den aktuellen Wert des Objekts benötigen und nicht möchten, dass dieser Wert Änderungen widerspiegelt, die von anderen Eigentümern des Objekts vorgenommen wurden.

Verwenden Sie diese Option, um eine flache Kopie des Objekts zu erstellen. Es empfiehlt sich, unveränderliche Eigenschaften immer auf Kopieren zu setzen. Da veränderbare Versionen in unveränderliche Eigenschaften übergeben werden können, wird durch Kopieren sichergestellt, dass Sie immer mit einem unveränderlichen Objekt arbeiten

Zuweisen Zuweisen ist etwas anders als Kopieren. Assign generiert einen Setter, der der Instanzvariablen den Wert direkt zuweist, anstatt ihn zu kopieren oder beizubehalten. Wenn der Getter einer Assign-Eigenschaft aufgerufen wird, wird ein Verweis auf die tatsächlichen Daten zurückgegeben.

8
Charles Owen

Andere Antworten sind alt, konnten keine gute Antwort bekommen.
Das folgende Beispiel bezieht sich auf Objektliterale und zeigt, wie beide sich ergänzen können und wie sie sich nicht ergänzen können (daher Unterschied):

var obj1 = { a: 1,  b: { b1: 1, b2: 'b2value', b3: 'b3value' } };

// overwrite parts of b key
var obj2 = {
      b: {
        ...obj1.b,
        b1: 2
      }
};
var res2 = Object.assign({}, obj1, obj2); // b2,b3 keys still exist
document.write('res2: ', JSON.stringify (res2), '<br>');
// Output:
// res2: {"a":1,"b":{"b1":2,"b2":"b2value","b3":"b3value"}}  // NOTE: b2,b3 still exists

// overwrite whole of b key
var obj3 = {
      b: {
        b1: 2
      }
};
var res3 = Object.assign({}, obj1, obj3); // b2,b3 keys are lost
document.write('res3: ', JSON.stringify (res3), '<br>');
// Output:
  // res3: {"a":1,"b":{"b1":2}}  // NOTE: b2,b3 values are lost

Hier noch ein paar kleine Beispiele, auch für Array & Objekt:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

Dies ist jetzt Teil von ES6, ist also standardisiert und auch auf MDN dokumentiert: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

Es ist sehr bequem zu bedienen und macht neben der Objektzerstörung auch sehr viel Sinn.

Der verbleibende Vorteil, der oben aufgeführt ist, sind die dynamischen Funktionen von Object.assign (). Dies ist jedoch so einfach wie das Verteilen des Arrays innerhalb eines Literalobjekts. In der kompilierten Ausgabe von babel wird genau das verwendet, was mit Object.assign () demonstriert wird.

Die richtige Antwort wäre also, Object Spread zu verwenden, da es jetzt standardisiert und weit verbreitet ist (siehe React, Redux usw.), einfach zu verwenden ist und alle Funktionen von Object.assign () aufweist.

0
Rikki Schulte