Warum ist Unveränderlichkeit in JavaScript so wichtig (oder erforderlich)?


204

Ich arbeite derzeit an React JS- und React Native- Frameworks. Auf halbem Weg stieß ich auf Immutability oder die Immutable-JS-Bibliothek , als ich über die Flux- und Redux-Implementierung von Facebook las.

Die Frage ist, warum Unveränderlichkeit so wichtig ist. Was ist falsch daran, Objekte zu mutieren? Macht es die Dinge nicht einfach?

Betrachten wir als Beispiel eine einfache Newsreader- App, deren Startbildschirm eine Listenansicht der Schlagzeilen ist.

Wenn ich ein Set sagt Array von Objekten mit einem Wert zunächst kann ich es nicht manipulieren. Das sagt das Unveränderlichkeitsprinzip, richtig? (Korrigieren Sie mich, wenn ich falsch liege.) Aber was ist, wenn ich ein neues News-Objekt habe, das aktualisiert werden muss? Im Normalfall hätte ich das Objekt einfach zum Array hinzufügen können. Wie erreiche ich in diesem Fall? Laden löschen und neu erstellen? Ist das Hinzufügen eines Objekts zum Array nicht eine kostengünstigere Operation?



2
Unveränderliche Datenstruktur und reine Funktion führen zu referenzieller Transparenz, wodurch es viel einfacher wird, über das Verhalten Ihres Programms nachzudenken. Bei Verwendung der funktionalen Datenstruktur erhalten Sie außerdem ein kostenloses Backtracking.
WorBlux

Ich habe einen Redux-Standpunkt @bozzmob angegeben.
Prosti

1
Es kann nützlich sein, etwas über Unveränderlichkeit im Allgemeinen als Konzept eines funktionalen Paradigmas zu lernen, anstatt zu glauben, dass JS etwas damit zu tun hat. React wird von Fans der funktionalen Programmierung geschrieben. Sie müssen wissen, was sie wissen, um sie zu verstehen.
Gherman

Es ist nicht notwendig, aber es bietet einige nette Kompromisse. Der veränderbare Zustand bezieht sich auf Software wie bewegliche Teile auf Hardware
Kristian Dupont

Antworten:


196

Ich habe kürzlich das gleiche Thema untersucht. Ich werde mein Bestes tun, um Ihre Frage (n) zu beantworten und zu teilen, was ich bisher gelernt habe.

Die Frage ist, warum Unveränderlichkeit so wichtig ist. Was ist falsch daran, Objekte zu mutieren? Macht es die Dinge nicht einfach?

Grundsätzlich kommt es darauf an, dass Unveränderlichkeit die Vorhersagbarkeit und Leistung (indirekt) erhöht und die Verfolgung von Mutationen ermöglicht.

Vorhersagbarkeit

Mutation verbirgt Veränderungen, die (unerwartete) Nebenwirkungen hervorrufen, die böse Fehler verursachen können. Wenn Sie Unveränderlichkeit erzwingen, können Sie Ihre Anwendungsarchitektur und Ihr mentales Modell einfach halten, was es einfacher macht, über Ihre Anwendung nachzudenken.

Performance

Obwohl das Hinzufügen von Werten zu einem unveränderlichen Objekt bedeutet, dass eine neue Instanz erstellt werden muss, in der vorhandene Werte kopiert und neue Werte zum neuen Objekt hinzugefügt werden müssen, was Speicher kostet, können unveränderliche Objekte die strukturelle Freigabe verwenden, um den Speicher zu reduzieren Overhead.

Alle Aktualisierungen geben neue Werte zurück, aber interne Strukturen werden gemeinsam genutzt, um die Speichernutzung (und das GC-Thrashing) drastisch zu reduzieren. Dies bedeutet, dass beim Anhängen an einen Vektor mit 1000 Elementen kein neuer Vektor mit einer Länge von 1001 Elementen erstellt wird. Intern werden höchstwahrscheinlich nur wenige kleine Objekte zugeordnet.

Mehr dazu lesen Sie hier .

Mutationsverfolgung

Neben der reduzierten Speichernutzung können Sie durch Unveränderlichkeit Ihre Anwendung optimieren, indem Sie Referenz- und Wertegleichheit verwenden. Dies macht es wirklich einfach zu sehen, ob sich etwas geändert hat. Zum Beispiel eine Zustandsänderung in einer Reaktionskomponente. Sie können verwenden shouldComponentUpdate, um zu überprüfen, ob der Status identisch ist, indem Sie Statusobjekte vergleichen und unnötiges Rendern verhindern. Mehr dazu lesen Sie hier .

Zusätzliche Ressourcen:

Wenn ich setze, sagen wir zunächst ein Array von Objekten mit einem Wert. Ich kann es nicht manipulieren. Das sagt das Unveränderlichkeitsprinzip, richtig? (Korrigieren Sie mich, wenn ich falsch liege). Aber was ist, wenn ich ein neues News-Objekt habe, das aktualisiert werden muss? Im Normalfall hätte ich das Objekt einfach zum Array hinzufügen können. Wie erreiche ich in diesem Fall? Laden löschen und neu erstellen? Ist das Hinzufügen eines Objekts zum Array nicht eine kostengünstigere Operation?

Ja das ist korrekt. Wenn Sie sich nicht sicher sind, wie Sie dies in Ihrer Anwendung implementieren sollen, würde ich Ihnen empfehlen, sich anzusehen, wie Redux dies tut, um sich mit den Kernkonzepten vertraut zu machen. Das hat mir sehr geholfen.

Ich verwende Redux gerne als Beispiel, weil es Unveränderlichkeit umfasst. Es hat einen einzelnen unveränderlichen Statusbaum (als bezeichnet store), in dem alle Statusänderungen explizit sind, indem Aktionen ausgelöst werden, die von einem Reduzierer verarbeitet werden, der den vorherigen Status zusammen mit diesen Aktionen akzeptiert (einzeln ) und den nächsten Status Ihrer Anwendung zurückgibt . Weitere Informationen zu den Grundprinzipien finden Sie hier .

Auf egghead.io gibt es einen ausgezeichneten Redux-Kurs, in dem Dan Abramov , der Autor von Redux, diese Prinzipien wie folgt erklärt (ich habe den Code ein wenig modifiziert, um besser zum Szenario zu passen):

import React from 'react';
import ReactDOM from 'react-dom';

// Reducer.
const news = (state=[], action) => {
  switch(action.type) {
    case 'ADD_NEWS_ITEM': {
      return [ ...state, action.newsItem ];
    }
    default: {
        return state;
    }
  }
};

// Store.
const createStore = (reducer) => {
  let state;
  let listeners = [];

  const subscribe = (listener) => {
    listeners.push(listener);

    return () => {
      listeners = listeners.filter(cb => cb !== listener);
    };
  };

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach( cb => cb() );
  };

  dispatch({});

  return { subscribe, getState, dispatch };
};

// Initialize store with reducer.
const store = createStore(news);

// Component.
const News = React.createClass({
  onAddNewsItem() {
    const { newsTitle } = this.refs;

    store.dispatch({
      type: 'ADD_NEWS_ITEM',
      newsItem: { title: newsTitle.value }
    });
  },

  render() {
    const { news } = this.props;

    return (
      <div>
        <input ref="newsTitle" />
        <button onClick={ this.onAddNewsItem }>add</button>
        <ul>
          { news.map( ({ title }) => <li>{ title }</li>) }
        </ul>
      </div>
    );
  }
});

// Handler that will execute when the store dispatches.
const render = () => {
  ReactDOM.render(
    <News news={ store.getState() } />,
    document.getElementById('news')
  );
};

// Entry point.
store.subscribe(render);
render();

Außerdem zeigen diese Videos detaillierter, wie Unveränderlichkeit erreicht werden kann für:


1
@naomik danke für das Feedback! Meine Absicht war es, das Konzept zu veranschaulichen und explizit zu zeigen, dass Objekte nicht mutiert werden, und nicht unbedingt zu zeigen, wie es vollständig implementiert werden kann. Mein Beispiel könnte jedoch etwas verwirrend sein. Ich werde es in Kürze aktualisieren.
Danillouz

2
@bozzmob du bist willkommen! Nein, das ist nicht korrekt. Sie müssen die Unveränderlichkeit des Reduzierers selbst erzwingen. Dies bedeutet, dass Sie Strategien folgen können, wie in den Videos gezeigt, oder eine Bibliothek wie unveränderliche js verwenden können. Weitere Informationen finden Sie hier und hier .
Danillouz

1
Bei @naomik ES6 constgeht es nicht um Unveränderlichkeit. Mathias Bynens hat einen großartigen Blog-Artikel darüber geschrieben.
Lea Rosema

1
@terabaud danke für das Teilen des Links. Ich stimme zu, dass es eine wichtige Unterscheidung ist. ^ _ ^
Danke

4
Bitte erläutern Sie Folgendes: "Mutation verbirgt Änderungen, die (unerwartete) Nebenwirkungen hervorrufen, die zu bösen Fehlern führen können. Wenn Sie die Unveränderlichkeit erzwingen, können Sie Ihre Anwendungsarchitektur und Ihr mentales Modell einfach halten, wodurch es einfacher wird, über Ihre Anwendung nachzudenken." Weil dies im Kontext von JavaScript überhaupt nicht stimmt.
Pavle Lekic

142

Eine konträre Sicht der Unveränderlichkeit

TL / DR: Unveränderlichkeit ist in JavaScript eher ein Modetrend als eine Notwendigkeit. Wenn Sie React verwenden, können einige verwirrende Entwurfsoptionen in der Statusverwaltung ordentlich umgangen werden. In den meisten anderen Situationen wird die damit verbundene Komplexität jedoch nicht ausreichend aufgewertet, da sie eher dazu dient , einen Lebenslauf aufzufüllen, als einen tatsächlichen Kundenbedarf zu decken.

Lange Antwort: lesen Sie unten.

Warum ist Unveränderlichkeit in Javascript so wichtig (oder notwendig)?

Nun, ich bin froh, dass du gefragt hast!

Vor einiger Zeit schrieb ein sehr talentierter Mann namens Dan Abramov eine Javascript State Management Library namens Redux, die reine Funktionen und Unveränderlichkeit verwendet. Er hat auch einige wirklich coole Videos gemacht , die die Idee wirklich leicht zu verstehen (und zu verkaufen) machten.

Das Timing war perfekt. Die Neuheit von Angular verblasste und die JavaScript-Welt war bereit, sich auf das Neueste zu konzentrieren, das den richtigen Grad an Coolness aufwies. Diese Bibliothek war nicht nur innovativ, sondern passte auch perfekt zu React, das von einem anderen Silicon Valley-Kraftpaket verkauft wurde .

So traurig es auch sein mag, in der Welt von JavaScript herrscht Mode. Jetzt wird Abramov als Halbgott gefeiert und wir Sterblichen müssen uns alle dem Dao der Unveränderlichkeit unterwerfen ... Ob es Sinn macht oder nicht.

Was ist falsch daran, Objekte zu mutieren?

Nichts!

Tatsächlich haben Programmierer Objekte für ähm ... mutiert, solange es Objekte zum Mutieren gab. Mit anderen Worten: Über 50 Jahre Anwendungsentwicklung.

Und warum die Dinge komplizieren? Wenn Sie ein Objekt haben catund es stirbt, brauchen Sie wirklich eine Sekunde cat, um die Änderung zu verfolgen? Die meisten Leute würden einfach sagen cat.isDead = trueund damit fertig sein.

Macht (mutierende Objekte) die Dinge nicht einfach?

JA! .. Natürlich tut es das!

Insbesondere in JavaScript, das in der Praxis am nützlichsten ist, um eine Ansicht eines Status zu rendern, der an anderer Stelle (wie in einer Datenbank) verwaltet wird.

Was ist, wenn ich ein neues News-Objekt habe, das aktualisiert werden muss? ... Wie erreiche ich in diesem Fall? Laden löschen und neu erstellen? Ist das Hinzufügen eines Objekts zum Array nicht eine kostengünstigere Operation?

Nun, Sie können den herkömmlichen Ansatz wählen und das NewsObjekt aktualisieren , sodass sich Ihre speicherinterne Darstellung dieses Objekts ändert (und die Ansicht, die dem Benutzer angezeigt wird, oder so würde man hoffen) ...

Oder alternativ...

Sie können den sexy FP / Immutability-Ansatz ausprobieren und Ihre Änderungen am NewsObjekt einem Array hinzufügen, das jede historische Änderung verfolgt, sodass Sie das Array durchlaufen und herausfinden können, wie die korrekte Zustandsdarstellung aussehen sollte (puh!).

Ich versuche zu lernen, was hier richtig ist. Bitte erleuchte mich :)

Mode kommt und geht Kumpel. Es gibt viele Möglichkeiten, eine Katze zu häuten.

Es tut mir leid, dass Sie die Verwirrung eines sich ständig ändernden Satzes von Programmierparadigmen ertragen müssen. Aber hey, willkommen im Club!

Nun ein paar wichtige Punkte, die Sie in Bezug auf Unveränderlichkeit beachten sollten, und Sie werden diese mit der fieberhaften Intensität auf Sie werfen, die nur Naivität aufbringen kann.

1) Unveränderlichkeit ist fantastisch, um Rennbedingungen in Umgebungen mit mehreren Threads zu vermeiden .

Multithread-Umgebungen (wie C ++, Java und C #) haben sich der Praxis schuldig gemacht, Objekte zu sperren, wenn mehr als ein Thread sie ändern möchte. Dies ist schlecht für die Leistung, aber besser als die Alternative der Datenbeschädigung. Und doch nicht so gut wie alles unveränderlich zu machen (Herr preise Haskell!).

ABER leider! In JavaScript arbeiten Sie immer mit einem einzelnen Thread . Sogar Web-Worker (jeder läuft in einem separaten Kontext ). Da Sie in Ihrem Ausführungskontext keine Thread-bezogenen Race-Bedingungen haben können (all diese schönen globalen Variablen und Abschlüsse), geht der Hauptpunkt zugunsten der Unveränderlichkeit aus dem Fenster.

(Having said that, es ist ein Vorteil der Verwendung von reinen Funktionen in Web - Arbeitern, die sind , dass Sie mit Objekten auf dem Haupt - Thread keine Erwartungen über das Hantieren haben werden.)

2) Unveränderlichkeit kann (irgendwie) Rennbedingungen im Zustand Ihrer App vermeiden.

Und hier ist der eigentliche Kern der Sache: Die meisten (React-) Entwickler werden Ihnen sagen, dass Unveränderlichkeit und FP diese Magie irgendwie anwenden können, die es ermöglicht, dass der Status Ihrer Anwendung vorhersehbar wird.

Dies bedeutet natürlich nicht, dass Sie Rennbedingungen in der Datenbank vermeiden können. Um diese zu erreichen, müssten Sie alle Benutzer in allen Browsern koordinieren. Dazu benötigen Sie eine Back-End-Push-Technologie wie WebSockets ( mehr dazu weiter unten), das Änderungen an alle überträgt, die die App ausführen.

Es bedeutet auch nicht, dass JavaScript ein inhärentes Problem aufweist, bei dem Ihr Anwendungsstatus unveränderlich sein muss, um vorhersehbar zu werden. Jeder Entwickler, der Front-End-Anwendungen vor React codiert hat, würde Ihnen dies mitteilen.

Diese ziemlich verwirrende Behauptung bedeutet einfach, dass mit React Ihr Bewerbungsstatus anfälliger für Rennbedingungen wird , aber dass Unveränderlichkeit es Ihnen ermöglicht, diesen Schmerz zu lindern. Warum? Da React etwas Besonderes ist, wurde es als hochoptimierte Rendering-Bibliothek konzipiert, wobei die kohärente Statusverwaltung an zweiter Stelle steht. Daher wird der Komponentenstatus über eine asynchrone Ereigniskette (auch als "Einweg-Datenbindung" bezeichnet) verwaltet, auf die Sie keinen Einfluss haben über und verlassen Sie sich darauf, dass Sie daran denken, den Zustand nicht direkt zu mutieren ...

In diesem Zusammenhang ist leicht zu erkennen, dass die Notwendigkeit der Unveränderlichkeit wenig mit JavaScript und viel mit den Rennbedingungen in React zu tun hat: Wenn Ihre Anwendung eine Reihe von voneinander abhängigen Änderungen enthält und keine einfache Möglichkeit besteht, herauszufinden, was Ihr Zustand befindet sich derzeit in einem Zustand, in dem Sie verwirrt sein werden. Daher ist es durchaus sinnvoll, die Unveränderlichkeit zu verwenden, um jede historische Veränderung zu verfolgen .

3) Die Rennbedingungen sind kategorisch schlecht.

Nun, sie könnten sein, wenn Sie React verwenden. Sie sind jedoch selten, wenn Sie ein anderes Framework auswählen.

Außerdem haben Sie normalerweise weitaus größere Probleme … Probleme wie die Hölle der Abhängigkeit. Wie eine aufgeblähte Codebasis. Als würde Ihr CSS nicht geladen. Wie ein langsamer Build-Prozess oder das Festhalten an einem monolithischen Back-End, das das Iterieren fast unmöglich macht. Wie unerfahrene Entwickler, die nicht verstehen, was los ist, und die Dinge durcheinander bringen.

Wissen Sie. Wirklichkeit. Aber hey, wen interessiert das?

4) Bei der Unveränderlichkeit werden Referenztypen verwendet , um die Auswirkungen der Verfolgung jeder Zustandsänderung auf die Leistung zu verringern.

Denn im Ernst, wenn Sie jedes Mal, wenn sich Ihr Status ändert, etwas kopieren, sollten Sie besser sicherstellen, dass Sie klug sind.

5) Unveränderlichkeit ermöglicht es Ihnen, Sachen rückgängig zu machen .

Weil ähm ... das ist die Nummer eins, nach der Ihr Projektmanager fragen wird, oder?

6) Unveränderlicher Zustand hat in Kombination mit WebSockets viel cooles Potenzial

Last but not least ist die Anhäufung von Zustandsdeltas in Kombination mit WebSockets ein ziemlich überzeugender Fall, der einen einfachen Verbrauch des Zustands als Fluss unveränderlicher Ereignisse ermöglicht ...

Sobald der Penny auf dieses Konzept fällt (Zustand ist ein Fluss von Ereignissen - und nicht eine grobe Reihe von Aufzeichnungen, die die neueste Sichtweise darstellen), wird die unveränderliche Welt zu einem magischen Ort zum Wohnen. Ein Land voller Wunder und Möglichkeiten, die über die Zeit hinausgehen . Und wenn es richtig getan kann auf jeden Fall machen Echtzeit - EASI apps er zu erreichen, Sie übertragen nur den Fluss der Ereignisse an alle Interessierten , so können sie ihre eigene Darstellung bauen der Gegenwart und schreiben ihre eigenen Änderungen in den kommunalen Fluss zurück.

Aber irgendwann wachst du auf und merkst, dass all diese Wunder und Magie nicht umsonst sind. Im Gegensatz zu Ihren eifrigen Kollegen kümmern sich Ihre Stakeholder (ja, die Leute, die Sie bezahlen) wenig um Philosophie oder Mode und viel um das Geld, das sie bezahlen, um ein Produkt zu bauen, das sie verkaufen können. Und das Fazit ist, dass es schwieriger ist, unveränderlichen Code zu schreiben und ihn leichter zu brechen. Außerdem macht es wenig Sinn, ein unveränderliches Front-End zu haben, wenn Sie kein Back-End haben, das ihn unterstützt. Wenn Sie (und wenn!) Ihre Stakeholder endgültig davon überzeugen, dass Sie Ereignisse über eine Push-Technologie wie WebSockets veröffentlichen und nutzen sollten, finden Sie heraus , wie schwierig es ist, die Produktion zu skalieren .


Nun zu einigen Ratschlägen, sollten Sie sich dafür entscheiden, diese zu akzeptieren.

Die Wahl, JavaScript mit FP / Immutability zu schreiben, ist auch eine Wahl, um Ihre Anwendungscodebasis größer, komplexer und schwieriger zu verwalten. Ich würde mich nachdrücklich dafür aussprechen, diesen Ansatz auf Ihre Redux-Reduzierungen zu beschränken, es sei denn, Sie wissen, was Sie tun ... Und wenn Sie die Unveränderlichkeit unabhängig davon verwenden, wenden Sie den unveränderlichen Status auf Ihren gesamten Anwendungsstapel an und nicht nur auf den clientseitig, da Ihnen sonst der wahre Wert fehlt.

Wenn Sie das Glück haben, Entscheidungen in Ihrer Arbeit treffen zu können, versuchen Sie, Ihre Weisheit zu nutzen (oder nicht) und tun Sie, was von der Person, die Sie bezahlt, richtig ist . Sie können dies auf Ihre Erfahrung, Ihren Bauch oder das, was um Sie herum vor sich geht, stützen (zugegebenermaßen, wenn jeder React / Redux verwendet, gibt es ein gültiges Argument dafür, dass es einfacher ist, eine Ressource zu finden, um Ihre Arbeit fortzusetzen). Sie können entweder Resume Driven Development- oder Hype Driven Development- Ansätze ausprobieren . Sie könnten eher deine Art von Dingen sein.

Kurz gesagt, die Sache, die für Unveränderlichkeit gesagt werden muss, ist, dass es Sie mit Ihren Kollegen in Mode bringt , zumindest bis der nächste Wahnsinn kommt, und an diesem Punkt werden Sie froh sein, weiterzumachen.


Nach dieser Selbsttherapiesitzung möchte ich darauf hinweisen, dass ich dies als Artikel in meinem Blog hinzugefügt habe => Unveränderlichkeit in JavaScript: Eine konträre Ansicht . Fühlen Sie sich frei, dort zu antworten, wenn Sie starke Gefühle haben, die Sie auch von Ihrer Brust bekommen möchten;).


10
Hallo Steven, ja. Ich hatte all diese Zweifel, als ich unveränderlich über Js und Redux nachdachte. Aber Ihre Antwort ist erstaunlich! Es bringt viel Wert und danke, dass Sie jeden einzelnen Punkt angesprochen haben, an dem ich Zweifel hatte. Es ist jetzt viel klarer / besser, selbst nachdem man monatelang an unveränderlichen Objekten gearbeitet hat.
Bozzmob

5
Ich benutze React with Flux / Redux seit über zwei Jahren und ich kann Ihnen nicht mehr zustimmen, tolle Antwort!
Pavle Lekic

6
Ich bin sehr misstrauisch, dass die Ansichten zur Unveränderlichkeit ziemlich genau mit den Team- und Codebasisgrößen korrelieren, und ich denke nicht, dass es ein Zufall ist, dass der Hauptvertreter ein Riese aus dem Silicon Valley ist. Davon abgesehen bin ich respektvoll anderer Meinung: Unveränderlichkeit ist eine nützliche Disziplin, wie die Nichtverwendung von goto eine nützliche Disziplin ist. Oder Unit-Tests. Oder TDD. Oder statische Typanalyse. Das bedeutet nicht, dass Sie sie jedes Mal die ganze Zeit machen (obwohl einige es tun). Ich würde auch sagen, dass Nützlichkeit orthogonal zum Hype ist: In einer Matrix aus nützlich / überflüssig und sexy / langweilig gibt es jeweils viele Beispiele. "hyped" !== "bad"
Jared Smith

4
Hallo @ftor, guter Punkt, Dinge zu weit in die andere Richtung zu gehen. Da es jedoch eine solche Fülle von Artikeln und Argumenten zur „Unveränderlichkeit in Javascript“ gibt, hatte ich das Gefühl, dass ich die Dinge ausgleichen musste. Neulinge haben also einen entgegengesetzten Standpunkt, der ihnen hilft, ein Urteil zu fällen.
Steven de Salas

4
Informativ und brillant betitelt. Bis ich diese Antwort fand, dachte ich, ich wäre der einzige, der eine ähnliche Ansicht vertritt. Ich erkenne den Wert der Unveränderlichkeit, aber was mich stört, ist, dass sie zu einem Dogma geworden ist, das alle anderen Techniken unterdrückt (z. B. zum Nachteil der 2-Wege-Bindung, die für die Eingabeformatierung, wie sie beispielsweise in KnockoutJS implementiert ist, wahnsinnig nützlich ist).
Tyblitz

53

Die Frage ist, warum Unveränderlichkeit so wichtig ist. Was ist falsch daran, Objekte zu mutieren? Macht es die Dinge nicht einfach?

Eigentlich ist das Gegenteil der Fall: Veränderlichkeit macht die Dinge zumindest auf lange Sicht komplizierter. Ja, es erleichtert Ihnen die anfängliche Codierung, da Sie die Dinge einfach ändern können, wo immer Sie möchten, aber wenn Ihr Programm größer wird, wird es zu einem Problem - wenn sich ein Wert geändert hat, was hat es geändert?

Wenn Sie alles unveränderlich machen, können Daten nicht mehr überraschend geändert werden. Sie wissen mit Sicherheit, dass ein Wert, der an eine Funktion übergeben wird, in dieser Funktion nicht geändert werden kann.

Einfach ausgedrückt: Wenn Sie unveränderliche Werte verwenden, ist es sehr einfach, über Ihren Code nachzudenken: Jeder erhält eine eindeutige * Kopie Ihrer Daten, sodass er nicht damit herumfummeln und andere Teile Ihres Codes beschädigen kann. Stellen Sie sich vor, wie viel einfacher dies das Arbeiten in einer Umgebung mit mehreren Threads macht!

Hinweis 1: Die Unveränderlichkeit verursacht potenzielle Leistungskosten, je nachdem, was Sie tun. Dinge wie Immutable.js werden jedoch so gut wie möglich optimiert.

Hinweis 2: In dem unwahrscheinlichen Fall, dass Sie sich nicht sicher waren, constbedeuten Immutable.js und ES6 sehr unterschiedliche Dinge.

Im Normalfall hätte ich das Objekt einfach zum Array hinzufügen können. Wie erreiche ich in diesem Fall? Laden löschen und neu erstellen? Ist das Hinzufügen eines Objekts zum Array nicht eine kostengünstigere Operation? PS: Wenn das Beispiel nicht der richtige Weg ist, um die Unveränderlichkeit zu erklären, lassen Sie mich bitte wissen, was das richtige praktische Beispiel ist.

Ja, Ihr Nachrichtenbeispiel ist vollkommen gut und Ihre Argumentation ist genau richtig: Sie können Ihre vorhandene Liste nicht einfach ändern, sondern müssen eine neue erstellen:

var originalItems = Immutable.List.of(1, 2, 3);
var newItems = originalItems.push(4, 5, 6);

1
Ich bin mit dieser Antwort nicht einverstanden, aber sie geht nicht auf seinen Teil der Frage "Ich möchte aus einem praktischen Beispiel lernen" ein. Man könnte argumentieren, dass ein einziger Verweis auf eine Liste von Nachrichtenkopfzeilen, die in mehreren Bereichen verwendet werden, eine gute Sache ist. "Ich muss die Liste nur einmal aktualisieren und alles, was auf die Nachrichtenliste verweist, wird kostenlos aktualisiert" - Ich denke, eine bessere Antwort würde ein häufiges Problem wie das von ihm vorgestellte annehmen und eine wertvolle Alternative zeigen, die Unveränderlichkeit nutzt.
Danke

1
Ich bin froh, dass die Antwort hilfreich war! In Bezug auf Ihre neue Frage: Versuchen Sie nicht, das System zu erraten :) In genau diesem Fall reduziert etwas, das als "strukturelles Teilen" bezeichnet wird, das GC-Thrashing dramatisch - wenn Sie 10.000 Elemente in einer Liste haben und 10 weitere hinzufügen, glaube ich, unveränderlich. js wird versuchen, die vorherige Struktur so gut wie möglich wiederzuverwenden. Lassen Sie Immutable.js sich Sorgen um das Gedächtnis machen, und es besteht die Möglichkeit, dass Sie feststellen, dass es besser herauskommt.
TwoStraws

6
Imagine how much easier this makes working in a multi-threaded environment!-> Ok für andere Sprachen, aber dies ist kein Vorteil in Single-Threaded-JavaScript.
Steven de Salas

1
@StevendeSalas beachten Sie, dass JavaScript hauptsächlich asynchron und ereignisgesteuert ist. Es ist überhaupt nicht immun gegen Rennbedingungen.
Jared Smith

1
@ JaredSmith noch mein Punkt bleibt. FP und Unveränderlichkeit sind äußerst nützliche Paradigmen, um Datenkorruption und / oder Ressourcensperren in Multithread-Umgebungen zu vermeiden, in JavaScript jedoch nicht, da es sich um Single-Threaded handelt. Wenn mir kein heiliges Nugget an Weisheit fehlt, ist der Hauptkompromiss hier, ob Sie bereit sind, Ihren Code komplexer (und langsamer) zu gestalten, um Rennbedingungen zu vermeiden ... die weitaus weniger problematisch sind als die meisten Menschen denken.
Steven de Salas

37

Obwohl die anderen Antworten in Ordnung sind, können Sie zur Beantwortung Ihrer Frage zu einem praktischen Anwendungsfall (aus den Kommentaren zu den anderen Antworten) für eine Minute aus Ihrem laufenden Code herausgehen und sich die allgegenwärtige Antwort direkt unter Ihrer Nase ansehen: git . Was würde passieren, wenn Sie jedes Mal, wenn Sie ein Commit drücken, die Daten im Repository überschreiben würden?

Jetzt haben wir eines der Probleme, mit denen unveränderliche Sammlungen konfrontiert sind: das Aufblähen des Gedächtnisses. Git ist intelligent genug, um nicht bei jeder Änderung einfach neue Kopien von Dateien zu erstellen, sondern einfach die Unterschiede zu verfolgen .

Obwohl ich nicht viel über das Innenleben von Git weiß, kann ich nur davon ausgehen, dass es eine ähnliche Strategie verwendet wie die Bibliotheken, auf die Sie verweisen: strukturelles Teilen. Unter der Haube verwenden die Bibliotheken Versuche oder andere Bäume, um nur die Knoten zu verfolgen, die sich unterscheiden.

Diese Strategie ist auch für speicherinterne Datenstrukturen einigermaßen leistungsfähig, da es bekannte Baumoperationsalgorithmen gibt, die in logarithmischer Zeit arbeiten.

Ein weiterer Anwendungsfall: Angenommen, Sie möchten eine Schaltfläche zum Rückgängigmachen in Ihrer Webanwendung. Bei unveränderlichen Darstellungen Ihrer Daten ist die Implementierung dieser Daten relativ trivial. Wenn Sie sich jedoch auf Mutationen verlassen, müssen Sie sich darum kümmern, den Zustand der Welt zwischenzuspeichern und atomare Aktualisierungen vorzunehmen.

Kurz gesagt, es gibt einen Preis für die Unveränderlichkeit der Laufzeitleistung und der Lernkurve. Jeder erfahrene Programmierer wird Ihnen jedoch sagen, dass die Debugging-Zeit die Code-Schreibzeit um eine Größenordnung überwiegt. Und die leichte Beeinträchtigung der Laufzeitleistung wird wahrscheinlich durch die staatlichen Fehler aufgewogen, die Ihre Benutzer nicht ertragen müssen.


1
Ein brillantes Beispiel, sage ich. Mein Verständnis von Unveränderlichkeit ist jetzt klarer. Danke Jared. Tatsächlich ist eine der Implementierungen die Schaltfläche UNDO: D Und Sie haben es mir ziemlich einfach gemacht.
Bozzmob

3
Nur weil ein Muster, das in Git Sinn macht, nicht bedeutet, dass dasselbe überall Sinn macht. In git kümmern Sie sich tatsächlich um den gesamten gespeicherten Verlauf und möchten in der Lage sein, verschiedene Zweige zusammenzuführen. Im Frontend interessiert Sie der größte Teil der Staatsgeschichte nicht und Sie brauchen nicht all diese Komplexität.
Ski

2
@Ski es ist nur komplex, weil es nicht die Standardeinstellung ist. Normalerweise verwende ich in meinen Projekten nicht mori oder immutable.js: Ich zögere immer, Deps von Drittanbietern zu übernehmen. Aber wenn das die Standardeinstellung wäre (a la clojurescript) oder zumindest eine native Option zum Anmelden hätte, würde ich sie die ganze Zeit verwenden, denn wenn ich zB in clojure programmiere, stopfe ich nicht sofort alles in Atome.
Jared Smith

Joe Armstrong würde sagen, mach dir keine Sorgen um die Leistung, warte nur ein paar Jahre und Moores Gesetz wird das für dich erledigen.
Ximo

1
@JaredSmith Sie haben Recht, die Dinge werden immer kleiner und ressourcenbeschränkter. Ich bin mir nicht sicher, ob dies der begrenzende Faktor für JavaScript sein wird. Wir finden immer wieder neue Wege, um die Leistung zu verbessern (zum Beispiel Svelte). Übrigens stimme ich Ihrem anderen Kommentar voll und ganz zu. Die Komplexität oder Schwierigkeit der Verwendung unveränderlicher Datenstrukturen hängt häufig davon ab, dass die Sprache das Konzept nicht unterstützt. Clojure macht Unveränderlichkeit einfach, weil es in die Sprache eingebrannt ist, die ganze Sprache wurde um die Idee herum entworfen.
Ximo

8

Die Frage ist, warum Unveränderlichkeit so wichtig ist. Was ist falsch daran, Objekte zu mutieren? Macht es die Dinge nicht einfach?

Über Veränderlichkeit

Aus technischer Sicht ist an der Veränderlichkeit nichts falsch. Es ist schnell, es verwendet den Speicher wieder. Entwickler sind von Anfang an daran gewöhnt (wie ich mich erinnere). Das Problem besteht in der Verwendung von Veränderlichkeit und Problemen, die diese Verwendung mit sich bringen kann.

Wenn das Objekt mit nichts geteilt wird, beispielsweise im Umfang der Funktion vorhanden ist und nicht nach außen zeigt, ist es schwierig, Vorteile in der Unveränderlichkeit zu erkennen. In diesem Fall macht es wirklich keinen Sinn, unveränderlich zu sein. Das Gefühl der Unveränderlichkeit beginnt, wenn etwas geteilt wird.

Mutabilitätskopfschmerz

Eine veränderbare gemeinsame Struktur kann leicht viele Fallstricke verursachen. Jede Änderung an einem Teil des Codes mit Zugriff auf die Referenz wirkt sich auf andere Teile mit Sichtbarkeit dieser Referenz aus. Ein solcher Aufprall verbindet alle Teile miteinander, auch wenn ihnen unterschiedliche Module nicht bekannt sein sollten. Eine Mutation in einer Funktion kann einen völlig anderen Teil der App zum Absturz bringen. So etwas ist eine schlimme Nebenwirkung.

Als nächstes ist das Problem mit der Mutation häufig ein beschädigter Zustand. Ein beschädigter Zustand kann auftreten, wenn das Mutationsverfahren in der Mitte fehlschlägt und einige Felder geändert wurden und andere nicht.

Darüber hinaus ist es bei Mutationen schwierig, die Änderung zu verfolgen. Eine einfache Referenzprüfung zeigt keinen Unterschied. Um zu wissen, was sich geändert hat, muss eine gründliche Prüfung durchgeführt werden. Um die Änderung zu überwachen, muss auch ein beobachtbares Muster eingeführt werden.

Schließlich ist die Mutation der Grund für das Vertrauensdefizit. Wie Sie sicher sein können, dass eine Struktur einen gewünschten Wert hat, wenn sie mutiert werden kann.

const car = { brand: 'Ferrari' };
doSomething(car);
console.log(car); // { brand: 'Fiat' }

Wie das obige Beispiel zeigt, kann das Übergeben einer veränderlichen Struktur immer mit einer anderen Struktur abgeschlossen werden. Die Funktion doSomething mutiert das von außen angegebene Attribut. Kein Vertrauen in den Code, Sie wissen wirklich nicht, was Sie haben und was Sie haben werden. All diese Probleme treten auf, weil: Veränderbare Strukturen Zeiger auf den Speicher darstellen.

Bei der Unveränderlichkeit geht es um Werte

Unveränderlichkeit bedeutet, dass Änderungen nicht an demselben Objekt und derselben Struktur vorgenommen werden, sondern dass Änderungen in neuen Objekten dargestellt werden. Und das liegt daran, dass die Referenz nicht nur den Speicherzeiger darstellt. Jede Änderung schafft neuen Wert und berührt den alten nicht. Solche klaren Regeln geben das Vertrauen und die Vorhersehbarkeit des Codes zurück. Funktionen sind sicher zu verwenden, da sie anstelle von Mutationen eigene Versionen mit eigenen Werten behandeln.

Die Verwendung von Werten anstelle von Speichercontainern gibt die Gewissheit, dass jedes Objekt einen bestimmten unveränderlichen Wert darstellt und sicher verwendet werden kann.

Unveränderliche Strukturen repräsentieren Werte.

Ich beschäftige mich noch mehr mit dem Thema in einem mittleren Artikel - https://medium.com/@macsikora/the-state-of-immutability-169d2cd11310


6

Warum ist Unveränderlichkeit in JavaScript so wichtig (oder erforderlich)?

Die Unveränderlichkeit kann in verschiedenen Kontexten verfolgt werden. Am wichtigsten ist jedoch, sie anhand des Anwendungsstatus und der Benutzeroberfläche der Anwendung zu verfolgen.

Ich werde das JavaScript-Redux-Muster als sehr trendigen und modernen Ansatz betrachten und weil Sie das erwähnt haben.

Für die Benutzeroberfläche müssen wir sie vorhersehbar machen . Es wird vorhersehbar sein, ob UI = f(application state).

Anwendungen (in JavaScript) ändern den Status über Aktionen, die mit der Reduzierungsfunktion implementiert werden .

Die Reduzierungsfunktion übernimmt einfach die Aktion und den alten Zustand und gibt den neuen Zustand zurück, wobei der alte Zustand intakt bleibt.

new state  = r(current state, action)

Geben Sie hier die Bildbeschreibung ein

Der Vorteil ist: Sie reisen zeitlich durch die Status, da alle Statusobjekte gespeichert sind, und Sie können die App seitdem in jedem Status rendern UI = f(state)

So können Sie einfach rückgängig machen / wiederholen.


Das Erstellen all dieser Zustände kann immer noch speichereffizient sein, eine Analogie zu Git ist großartig, und wir haben die ähnliche Analogie unter Linux mit symbolischen Links (basierend auf den Inodes).


5

Ein weiterer Vorteil der Unveränderlichkeit in Javascript besteht darin, dass die zeitliche Kopplung verringert wird, was im Allgemeinen erhebliche Vorteile für das Design hat. Betrachten Sie die Schnittstelle eines Objekts mit zwei Methoden:

class Foo {

      baz() {
          // .... 
      }

      bar() {
          // ....
      }

}

const f = new Foo();

Es kann vorkommen, dass ein Aufruf von baz()erforderlich ist, um das Objekt in einen gültigen Zustand zu versetzen, bar()damit ein Aufruf ordnungsgemäß funktioniert. Aber woher weißt du das?

f.baz();
f.bar(); // this is ok

f.bar();
f.baz(); // this blows up

Um dies herauszufinden, müssen Sie die Interna der Klasse überprüfen, da dies bei der Untersuchung der öffentlichen Schnittstelle nicht sofort ersichtlich ist. Dieses Problem kann in einer großen Codebasis mit vielen veränderlichen Zuständen und Klassen explodieren.

Wenn Foounveränderlich, ist dies kein Problem mehr. Es ist sicher anzunehmen, dass wir anrufen können bazoder barin beliebiger Reihenfolge, da sich der innere Zustand der Klasse nicht ändern kann.


4

Es war einmal ein Problem mit der Datensynchronisation zwischen Threads. Dieses Problem war ein großer Schmerz, es gab mehr als 10 Lösungen. Einige Leute versuchten es radikal zu lösen. Es war ein Ort, an dem funktionale Programmierung geboren wurde. Es ist wie im Marxismus. Ich konnte nicht verstehen, wie Dan Abramov diese Idee an JS verkauft hat, weil sie Single-Threaded ist. Er ist ein Genie.

Ich kann ein kleines Beispiel geben. __attribute__((pure))In gcc gibt es ein Attribut . Compiler versuchen zu lösen, ob Ihre Funktion rein ist oder nicht, wenn Sie sie nicht speziell deklarieren. Ihre Funktion kann rein sein, auch wenn Ihr Zustand veränderlich ist. Unveränderlichkeit ist nur eine von über 100 Möglichkeiten, um sicherzustellen, dass Ihre Funktion rein ist. Tatsächlich sind 95% Ihrer Funktionen rein.

Sie sollten keine Einschränkungen (wie Unveränderlichkeit) anwenden, wenn Sie tatsächlich keinen ernsthaften Grund haben. Wenn Sie einen Status "rückgängig machen" möchten, können Sie Transaktionen erstellen. Wenn Sie die Kommunikation vereinfachen möchten, können Sie Ereignisse mit unveränderlichen Daten senden. Es liegt an dir.

Ich schreibe diese Nachricht aus der Postmarxismus-Republik. Ich bin sicher, dass die Radikalisierung einer Idee ein falscher Weg ist.


Der 3. Absatz macht so viel Sinn. Danke für das. 'Wenn Sie einen Status "rückgängig machen" möchten, können Sie Transaktionen erstellen' !!
Bozzmob

Der Vergleich zum Marxismus kann übrigens auch für OOP gemacht werden. Erinnerst du dich an Java? Heck, die ungeraden Teile von Java in JavaScript? Hype ist niemals gut, er verursacht Radikalisierung und Polarisierung. Historisch gesehen war OOP viel mehr gehyped als Facebooks Hyping von Redux. Obwohl sie sicher ihr Bestes gegeben haben.
Ximo

4

Eine andere Einstellung ...

Meine andere Antwort befasst sich mit der Frage von einem sehr praktischen Standpunkt aus, und ich mag sie immer noch. Ich habe beschlossen, dies als eine andere Antwort und nicht als Nachtrag zu dieser hinzuzufügen, da es eine langweilige philosophische Parole ist, die hoffentlich auch die Frage beantwortet, aber nicht wirklich zu meiner bestehenden Antwort passt.

TL; DR

Selbst in kleinen Projekten kann Unveränderlichkeit nützlich sein, aber nehmen Sie nicht an, dass sie für Sie bestimmt ist, weil sie existiert.

Viel, viel länger antworten

HINWEIS: Für die Zwecke dieser Antwort verwende ich das Wort "Disziplin", um Selbstverleugnung für einen gewissen Nutzen zu bedeuten.

Dies ähnelt in seiner Form einer anderen Frage: "Soll ich Typescript verwenden? Warum sind Typen in JavaScript so wichtig?". Es hat auch eine ähnliche Antwort. Stellen Sie sich das folgende Szenario vor:

Sie sind der alleinige Autor und Betreuer einer JavaScript / CSS / HTML-Codebasis mit etwa 5000 Zeilen. Ihr halbtechnischer Chef liest etwas über Typescript-as-the-new-hotness und schlägt vor, dass wir vielleicht dorthin wechseln möchten, überlässt die Entscheidung jedoch Ihnen. Also liest du darüber, spielst damit usw.

Nun haben Sie die Wahl, wechseln Sie zu Typescript?

Typescript bietet einige überzeugende Vorteile: Intellisense, frühzeitiges Erkennen von Fehlern, Festlegen Ihrer APIs im Voraus, einfache Behebung von Problemen, wenn das Refactoring sie unterbricht, weniger Tests. Typoskript hat auch einige Kosten: Bestimmte sehr natürliche und korrekte JavaScript-Redewendungen können in seinem nicht besonders leistungsfähigen Typsystem schwierig zu modellieren sein, Anmerkungen erhöhen die LoC, Zeit und Aufwand für das Umschreiben der vorhandenen Codebasis, zusätzliche Schritte in der Build-Pipeline usw. Grundsätzlich wird eine Teilmenge möglicher korrekter JavaScript-Programme herausgearbeitet, um das Versprechen zu erhalten, dass Ihr Code mit größerer Wahrscheinlichkeit korrekt ist. Es ist willkürlich restriktiv. Das ist der springende Punkt: Sie erzwingen eine Disziplin, die Sie einschränkt (hoffentlich, indem Sie sich in den Fuß schießen).

Zurück zu der Frage, die im Zusammenhang mit dem obigen Absatz umformuliert wurde: Lohnt es sich ?

In dem beschriebenen Szenario würde ich behaupten, dass die Wahl der Verwendung von Typescript eher ästhetisch als praktisch ist, wenn Sie mit einer kleinen bis mittelmäßigen JS-Codebasis sehr vertraut sind. Und das ist in Ordnung , an der Ästhetik ist nichts auszusetzen , sie ist einfach nicht unbedingt überzeugend.

Szenario B:

Sie wechseln den Job und sind jetzt Branchenprogrammierer bei Foo Corp. Sie arbeiten mit einem 10-köpfigen Team an einer JavaScript / HTML / CSS-Codebasis mit 90000 LoC (und Zählung) und einer ziemlich komplizierten Build-Pipeline mit Babel, Webpack , eine Reihe von Polyfills, reagieren mit verschiedenen Plugins, einem Statusverwaltungssystem, ~ 20 Bibliotheken von Drittanbietern, ~ 10 internen Bibliotheken, Editor-Plugins wie einem Linter mit Regeln für den internen Styleguide usw. usw.

Damals, als du ein 5k LoC-Typ / Mädchen warst, war es einfach nicht so wichtig. Sogar die Dokumentation war keine so große Sache, selbst wenn man nach 6 Monaten auf einen bestimmten Teil des Codes zurückkam, konnte man es leicht genug herausfinden. Aber jetzt ist Disziplin nicht nur nett, sondern notwendig . Dass Disziplin nicht beinhalten Typoskript, sondern wird wahrscheinlich irgendeine Form von statischen Analyse sowie alle anderen Formen der Codierung Disziplin (Dokumentation, Styleguide, Build - Skripte, Regressionstests, CI) beinhalten. Disziplin ist kein Luxus mehr , sondern eine Notwendigkeit .

All dies galt GOTO1978: Ihr versautes kleines Blackjack-Spiel in C konnte GOTOs- und Spaghetti-Logik verwenden, und es war einfach keine so große Sache, Ihr eigenes Abenteuer zu wählen, aber als die Programme größer wurden und Ein ehrgeizigerer, undisziplinierterer Einsatz GOTOkonnte nicht aufrechterhalten werden. Und das alles gilt heute für die Unveränderlichkeit.

Genau wie bei statischen Typen ist die Wahl der Unveränderlichkeit eher ästhetisch als praktisch, wenn Sie nicht an einer großen Codebasis mit einem Team von Ingenieuren arbeiten, die diese warten / erweitern. Die Vorteile sind immer noch vorhanden, überwiegen jedoch möglicherweise noch nicht die Kosten.

Aber wie bei allen nützlichen Disziplinen kommt ein Punkt, an dem dies nicht mehr optional ist. Wenn ich ein gesundes Gewicht halten möchte, kann Disziplin mit Eis optional sein. Wenn ich jedoch ein Leistungssportler sein möchte, hängt meine Entscheidung, ob ich Eis essen möchte oder nicht, von meiner Wahl der Ziele ab. Wenn Sie die Welt mit Software verändern möchten, ist Unveränderlichkeit möglicherweise Teil dessen, was Sie benötigen, um zu verhindern, dass sie unter ihrem eigenen Gewicht zusammenbricht.


1
+1 Ich mag es. Viel mehr zum Punkt Jared. Und doch wird Unveränderlichkeit ein Team nicht vor seiner eigenen mangelnden Disziplin retten. 😉
Steven de Salas

@StevendeSalas ist eine Form der Disziplin. Und als solches denke ich, dass es mit den anderen Formen der Software-Engineering-Disziplin korreliert (aber diese nicht ersetzt). Es ergänzt und ersetzt nicht. Aber wie ich in einem Kommentar zu Ihrer Antwort sagte, wundert es mich überhaupt nicht, dass es von einem Technologieriesen mit einer Gruppe von Ingenieuren vorangetrieben wird, die alle auf derselben riesigen Codebasis herumschleifen :) Sie brauchen alle Disziplin, die sie bekommen können. Ich mutiere zum größten Teil keine Objekte, verwende aber auch keine Form der Durchsetzung, da ich es nur bin.
Jared Smith

0

Ich habe eine Framework-agnostische Open-Source-Bibliothek (MIT) für den veränderlichen (oder unveränderlichen) Zustand erstellt, die alle unveränderlichen Speicher wie Bibliotheken (Redux, Vuex usw.) ersetzen kann.

Unveränderliche Zustände waren für mich hässlich, weil zu viel Arbeit zu erledigen war (viele Aktionen für einfache Lese- / Schreibvorgänge), Code weniger lesbar war und die Leistung für große Datenmengen nicht akzeptabel war (erneutes Rendern der gesamten Komponente: /).

Mit Deep-State-Observer kann ich nur einen Knoten mit Punktnotation aktualisieren und Platzhalter verwenden. Ich kann auch einen Statusverlauf erstellen (Rückgängig / Wiederherstellen / Zeitreise), wobei nur die konkreten Werte beibehalten werden, die geändert wurden {path:value}= weniger Speicherbedarf.

Mit Deep-State-Observer kann ich Feinabstimmungen vornehmen und habe die Kontrolle über das Verhalten der Komponenten, sodass die Leistung drastisch verbessert werden kann. Code ist besser lesbar und Refactoring ist viel einfacher - suchen und ersetzen Sie einfach Pfadzeichenfolgen (Code / Logik müssen nicht geändert werden).


-1

Ich denke, der Hauptgrund für unveränderliche Objekte ist, den Zustand des Objekts gültig zu halten.

Angenommen, wir haben ein Objekt namens arr. Dieses Objekt ist gültig, wenn alle Elemente denselben Buchstaben haben.

// this function will change the letter in all the array
function fillWithZ(arr) {
    for (var i = 0; i < arr.length; ++i) {
        if (i === 4) // rare condition
            return arr; // some error here

        arr[i] = "Z";
    }

    return arr;
}

console.log(fillWithZ(["A","A","A"])) // ok, valid state
console.log(fillWithZ(["A","A","A","A","A","A"])) // bad, invalid state

Wenn es sich arrum ein unveränderliches Objekt handelt, sind wir sicher, dass arr immer in einem gültigen Zustand ist.


Ich denke, arrwird jedes Mal mutiert, wenn Sie anrufenfillWithZ
rodrigo-silveira

Wenn Sie immutable.js verwenden, erhalten Sie bei jeder Änderung eine neue Kopie des Objekts. so bleibt das ursprüngliche Objekt unberührt
bedorlan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.