J o: Javascript Referenzen

Moin,

ich hab eine Frage zu Referenzen. Dazu ein kleines Beispiel:

var data = {a: 1, b: 2, c:3};

var f = function(){
	this.a = data.a; //Keine Referenz?
  this.d = data; //Referenz
  this.geta = function(){
  	return this.a;
  }
  this.getd = function(){
  	return this.d;
  }
}

var foo = new f();

Object.assign(data, {a: 5, d:6}); // ändert f.d
																	// ändert f.a NICHT

console.log(foo.geta());
console.log(foo.getd());

Erstens, warum ist this.a = data.a; anscheinend keine Referenz? Beziehungsweise was ist mein Denkfehler?
Und Zweitens, wie kann man eine Referenz auf eine Eigenschaft eines Objektes erzeugen. (Möchte das ungern mit "setter-Funktionen" machen, da sich das durch sehr viele Instanzen zeiht).

Gruß
Jo

akzeptierte Antworten

  1. Tach!

    Erstens, warum ist this.a = data.a; anscheinend keine Referenz? Beziehungsweise was ist mein Denkfehler?

    Bei primitiven Typen wird der Wert übergeben, da sie einfach kopiert werden können. Objekte können beliebig verschachtelt sein, auch rekursiv, da wird der Einfachheit halber eine Referenz weitergegeben.

    Und Zweitens, wie kann man eine Referenz auf eine Eigenschaft eines Objektes erzeugen.

    Meines Wissens nach gar nicht, wenn es sich dabei um primitive Typen handelt. Du könntest den Wert in ein Objekt betten, à la new Number(42), aber das gibt keinen Vorteil. Der Wert dieses Objekts ist nicht änderbar. Wenn du der Eigenschaft deines Objekts ein neues solches Wrapper-Objekt zuweist, bricht das genauso die Referenz wie wenn du vorher den Wert kopiert hättest.

    data.a = 42
    a = data.a; // Kopie
    data.a = 23;
    // a ist immer noch 42
    
    data.a = new Number(42)
    a = data.a; // Referenz
    data.a = new Number(23);
    // a ist immer noch Number(42)
    

    dedlfix.

    1. Hey,

      Erstens, warum ist this.a = data.a; anscheinend keine Referenz? Beziehungsweise was ist mein Denkfehler?

      Bei primitiven Typen wird der Wert übergeben, da sie einfach kopiert werden können. Objekte können beliebig verschachtelt sein, auch rekursiv, da wird der Einfachheit halber eine Referenz weitergegeben.

      Auch Eigenschaften die wiederum Objekt sind werden nicht referenziert.

      Und Zweitens, wie kann man eine Referenz auf eine Eigenschaft eines Objektes erzeugen.

      [...] Der Wert dieses Objekts ist nicht änderbar. Wenn du der Eigenschaft deines Objekts ein neues solches Wrapper-Objekt zuweist, bricht das genauso die Referenz wie wenn du vorher den Wert kopiert hättest.

      Dann werde ich wohl um set a() nicht herum kommen. Vielen Dank!

      Gruß
      Jo

      1. Tach!

        Auch Eigenschaften die wiederum Objekt sind werden nicht referenziert.

        Object.assign(data, {a: { x: 5, y: 9 }, d:6});

        Wenn du data.a mit einem neuen Objekt überschreibst, zeigen die angelegten Referenzen weiterhin auf das alte Objekt. Wenn du stattdessen data.a.x = 5 nimmst, wirst du den Unterschied sehen. a bleibt erhalten und dessen Eingenschaft 5 bekommt einen neuen Wert zugewiesen.

        dedlfix.

        1. Tach!

          Auch Eigenschaften die wiederum Objekt sind werden nicht referenziert.

          Object.assign(data, {a: { x: 5, y: 9 }, d:6});

          Wenn du data.a mit einem neuen Objekt überschreibst, zeigen die angelegten Referenzen weiterhin auf das alte Objekt. Wenn du stattdessen data.a.x = 5 nimmst, wirst du den Unterschied sehen. a bleibt erhalten und dessen Eingenschaft 5 bekommt einen neuen Wert zugewiesen.

          Ja, aber das wäre zu komplex, bzw wären zu viele Zeilen.

          Gruß
          Jo

  2. Hallo Jo,

    die aus PHP oder C++ bekannten Referenzen auf beliebige Variablen gibt es in JavaScript nicht.

    Aber vielleicht kannst Du Dich mit einem selbstgebaunten Funktor[1] behelfen?

    let SomeClass = function() {
       this.a = 17;
    };
    
    let makeRefFunctor = function (obj, property) {
       return function(newValue) {
          return (arguments.length > 0) ?
             (obj[property] = newValue) :
             obj[property];
      }
    }
    
    let obj = new SomeClass();
    let refA = makeRefFunctor(obj, "a");
    
    console.log(refA());
    refA(32);
    console.log(refA());
    

    SomeClass ist eine beliebige Klasse mit der Eigenschaft a.

    makeReference erzeugt eine anonyme Funktion, die einen optionalen Parameter newValue bekommt. Da dieses Funktionsobjekt den Scope dieses makeReference-Aufrufs als Closure mitnimmt und später auch nutzt, wird es zum Funktor, der für ein bestimmtes Objekt eine bestimmte Eigenschaft lesen und schreiben kann.

    Der Funktor muss eine richtige Funktion sein, keine Pfeilfunktion, damit arguments definiert ist. Damit kann man abfragen, wieviele Parameter übergeben wurden und so steuern, ob der Funktor als getter oder setter agieren soll.

    Alternativ kann man auch eine Klasse PropertyRef bauen. Die macht nichts anderes als der Funktor, speichert aber Objekt und Propertyname explizit und steuert den Zugriff über getter und setter einer Value-Eigenschaft.

    class PropertyRef {
       constructor(obj, property) {
          this.object = obj;
          this.property = property;
       }
    	get value() { return this.object[this.property]; }
    	set value(newValue) { this.object[this.property] = newValue; }
    }
    
    let obj = new SomeClass();
    let pRefA = new PropertyRef(obj, "a");
    
    console.log(pRefA.value);
    pRefA.value = 47;
    console.log(pRefA.value);
    

    Rolf

    --
    sumpsi - posui - clusi

    1. Definition Funktor in C++: Ein Objekt, das den Operator () überlädt. Letztlich ist das in JavaScript für jede Funktion der Fall; ein Funktor hat aber im Gegensatz zu einer normalen Funktion die Möglichkeit, sich Informationen zu merken. Das verwenden wir hier. ↩︎

  3. Hey,

    Man könnte es sich auch einfach einfach machen:

    var data = {a: { x: 1, y: 2 }, b: 2, c:3};
    
    var f = function(d){
      this.getd = function(){
      	return d;
      }
    }
    var foo = new f(data);
    

    Gruß
    Jo