2017-10-27 4 views
2

Dies ist eine Frage dazu, wie JavaScript einen Verweis auf vorhandene hinzufügen kann, anstatt neue zu erstellen.Behält JavaScript einen Verweis auf vorhandene Variablen bei, wenn Objekte mithilfe der Objektliteralsyntax erstellt werden?

Hier sind einige Beispiele, die hoffentlich illustrativ-genug, im Rahmen eines Redux Minderer sind, weil es ein vertrauter Ort für spread operator oder Object.assign() ist:

Hier sehen wir kehren nur eine wörtliche Objekt mit einem String, also gibt es nichts, was in einer Referenz zu etwas ziehen könnte, das an anderer Stelle existiert.

export default (state = {}, action) => { 
    switch (action.type) { 
     case SOME_ACTION: 
      return { 
       props: 'something arbitray' 
      } 
    } 
} 

Dieses ist der Verdächtige Problem:

Wir ein Objektliteral zurückkehren, aber wir haben Bezug auf args[type] enthalten. Zuerst muss ich sicher wissen, ob dies ein Objekt zurückgibt, das einen Link zu was auch immer args[type] derzeit festgelegt ist? Wenn args[type] später mutiert werden, würde dies in diesem zurückgegebenen Objekt widergespiegelt werden?

export default (state = {}, action) => { 
    switch (action.type) { 
     case SOME_ACTION: 
      return { 
       props: args[type] 
      } 
    } 
} 

Hier sind zwei Beispiele, die ich vermute, würde dieses Problem nicht:

Verstehe ich das richtig? Kopiert JavaScript nur die Eigenschaft und behält keinen Bezug auf args[type]?

export default (state = {}, action) => { 
    switch (action.type) { 
     case SOME_ACTION: 
      return Object.assign({}, state, { props: args[type] }) 
    } 
} 

Hier ist ein weiteres Beispiel, das ich könnte syntaktisch identisch sein mit dem Object.assign() Syntax vor kurzem gelernt:

export default (state = {}, action) => { 
    switch (action.type) { 
     case SOME_ACTION: 
      return { ...state, props: args[type] } 
    } 
} 

Die Fragen:

  1. Ist der Spread Betreiber tun das gleiche wie Object.assign() in diesem Zusammenhang und erstellen ein völlig neues Objekt ohne Risiko der illegalen Veränderung durch die Beibehaltung eines Verweises auf args[type]? Ich muss mich auf den unveränderlichen Zustand des Objekts verlassen können, nachdem es erstellt wurde.

  2. Würde das zweite Beispiel, das ich zeigte, eine Live-Referenz zu args[type] beibehalten?

Ich habe einige Code, der normalerweise in etwas verbreitet, und ich habe einen Anwendungsfall, der diese Verbreitung auslässt, so dass ich bin gespannt, ob das ein Problem sein könnte. Wie kann ich garantieren, dass zufällige Änderungen von args[type] dieses zurückgegebene Objekt nicht beeinträchtigen?

Wäre das die richtige Antwort?:

export default (state = {}, action) => { 
    switch (action.type) { 
     case SOME_ACTION: 
      return Object.assign({}, { props: args[type] }) 
    } 
} 

[bearbeiten] Ich bin das Problem reproduzieren können, indem Sie diese:

const arr = ['one', 'two', 'three'] 
 

 
const args = { 
 
    type: arr 
 
} 
 

 
const something = { 
 
    props: args.type 
 
} 
 

 
arr.push('four') // Notice how this appears in something.props 
 

 
console.log(something)

Und dies behebt es (so scheint es, etwas zu haben, mit Primitiven im Vergleich zur Pflege einer Objektreferenz):

const arr = ['one', 'two', 'three'] 
 

 
const args = { 
 
    type: arr[2] 
 
} 
 

 
const something = { 
 
    props: args.type 
 
} 
 

 
arr[2] = 'what' // Notice how this doesn't appear in something.props 
 

 
console.log(something)

Aktualisiert Frage

Gibt es eine Möglichkeit, einen non-primitive zu kopieren (dh: Objekt/Array), so dass sie diese Referenz bricht?

Ich bemerkte es nicht mit Object.assign()

Antwort

3

var a = 5; var b = a;

Does b a behält einen Verweis funktioniert? Nein, tut es nicht. Sie übergeben einen Wert Verweis/Wert und nicht das übergeordnete Objekt.

+0

Es ist, weil ein primitiv ist. probiere 'var a = [5]; var b = a; a.push (2); console.log (b); ' – agm1984

+0

Ich möchte wissen, wie ich sicherstellen kann, dass dieses Verhalten nicht auftritt. – agm1984

+0

In Ihrem Beispiel hat b immer noch keinen Bezug zu a. Sie zeigen beide auf dasselbe Objekt, aber nicht auf einander. dh. wenn Sie "a" etwas anderes zuweisen. und dann irgendeine Operation an "a". Das hat keinen Einfluss auf "b". –

0

Die Antwort scheint zu sein, dass es kein Problem ist, wenn der Wert ein Primitiv ist, weil JavaScript keine Verweise auf Primitive speichert.

Die hier Lösung ist in dem Objekt oder ein Array als eine Eigenschaft zu verbreiten:

const arr = ['one', 'two', 'three'] 
 

 
const args = { 
 
    type: arr 
 
} 
 

 
const something = { 
 
    props: [...args.type] 
 
} 
 

 
arr.push('four') // notice how this isn't included 
 

 
console.log(something)

Dies ist hilfreich: Is JavaScript a pass-by-reference or pass-by-value language?

vs tiefem Kopieren über seichte Lese ist auch hilfreich , Hard Copy vs Shallow copy javascript

Dies löst das Problem, wenn das Ziel t ist ein Ziel:

const obj = { 
 
    one: 'uno', 
 
    two: 'dos', 
 
    three: 'tres' 
 
} 
 

 
const args = { 
 
    type: obj 
 
} 
 

 
const something = { 
 
    props: Object.assign({}, args.type) 
 
} 
 

 
obj.four = 'four' // notice how this isn't included 
 

 
console.log(something)

Ich erinnere daran, dies auch in einem Buch von Eric Elliot beschrieben. Object.assign() ist der Schlüssel zum Verlassen dieser Referenz. (und jetzt im Jahr 2017, verteilt)

+2

Die wirkliche Antwort könnte sein, den Wert nicht zu mutieren, wie es das Unvermeidbarkeits-Tag auf deiner Frage andeutet :-) – Bergi

+0

Das machen wir, aber ich muss es genug verstehen, um richtig darüber zu argumentieren! – agm1984

+1

Sie sollten wahrscheinlich auch den Unterschied zwischen Neuzuordnungen und Mutationen kennen. Javascript speichert niemals Referenzen, sondern immer Werte, auch für Objekttypen. Wenn Sie einer Variablen einen Objekttyp zuweisen, wird eine Kopie der Referenz auf dieses Objekt gespeichert, nicht die Referenz selbst. Dieser feine Unterschied ist wichtig, um die Evaluierungsstrategie von Javascript zu verstehen. – ftor

Verwandte Themen