918 Stimmen

Selbstreferenzen in Objektliteralen/Initialisierern

Gibt es eine Möglichkeit, so etwas wie das Folgende in JavaScript zum Laufen zu bringen?

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Doesn't work
};

In der aktuellen Form führt dieser Code offensichtlich zu einem Referenzfehler, da this bezieht sich nicht auf foo . Aber ist Gibt es eine Möglichkeit, die Werte in den Eigenschaften eines Objektliterales von anderen, früher deklarierten Eigenschaften abhängig zu machen?

27voto

Henry Wrightson Punkte 259

Dies sollte durch einen Abschluss geregelt werden;

var foo = function() {
    var a = 5;
    var b = 6;
    var c = a + b;

    return {
        a: a,
        b: b,
        c: c
    }
}();

Alle Variablen, die innerhalb von foo sind privat für foo wie Sie es bei jeder Funktionsdeklaration erwarten würden, und da sie sich alle im Geltungsbereich befinden, können sie alle aufeinander zugreifen, ohne dass sie sich auf this so wie man es bei einer Funktion erwarten würde. Der Unterschied besteht darin, dass diese Funktion ein Objekt zurückgibt, das die privaten Variablen offenlegt und dieses Objekt an foo . Am Ende geben Sie nur die Schnittstelle zurück, die Sie als Objekt mit der Option return {} Erklärung.

Die Funktion wird dann am Ende mit der () was dazu führt, dass das gesamte foo-Objekt ausgewertet wird, alle Variablen darin instanziiert werden und das Rückgabeobjekt als Eigenschaften von foo() .

18voto

davedambonite Punkte 161

Das könnte man so machen

var a, b
var foo = {
    a: a = 5,
    b: b = 6,
    c: a + b
}

Diese Methode hat sich für mich als nützlich erwiesen, wenn ich auf das Objekt verweisen musste, für das eine Funktion ursprünglich deklariert wurde. Nachfolgend ein minimales Beispiel, wie ich sie verwendet habe:

function createMyObject() {
    var count = 0, self
    return {
        a: self = {
            log: function() {
                console.log(count++)
                return self
            }
        }
    }
}

Indem Sie self als das Objekt definieren, das die Druckfunktion enthält, erlauben Sie der Funktion, sich auf dieses Objekt zu beziehen. Das bedeutet, dass Sie die Druckfunktion nicht an ein Objekt "binden" müssen, wenn Sie sie an eine andere Stelle übergeben müssen.

Wenn Sie stattdessen this wie unten dargestellt

function createMyObject() {
    var count = 0
    return {
        a: {
            log: function() {
                console.log(count++)
                return this
            }
        }
    }
}

Dann wird der folgende Code 0, 1, 2 protokollieren und dann einen Fehler ausgeben

var o = createMyObject()
var log = o.a.log
o.a.log().log() // this refers to the o.a object so the chaining works
log().log() // this refers to the window object so the chaining fails!

Durch die Verwendung der self-Methode garantieren Sie, dass print immer dasselbe Objekt zurückgibt, unabhängig vom Kontext, in dem die Funktion ausgeführt wird. Der obige Code läuft einwandfrei und protokolliert 0, 1, 2 und 3, wenn Sie die self-Version von createMyObject() .

12voto

monzonj Punkte 3539

Zur Vervollständigung haben wir in ES6 Klassen (die zum Zeitpunkt der Erstellung dieses Artikels nur von den neuesten Browsern unterstützt werden, aber in Babel, TypeScript und anderen Transpilern verfügbar sind)

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();

8voto

animaacija Punkte 150

Nur mal so zum Nachdenken - platzieren Sie die Eigenschaften des Objekts außerhalb einer Zeitleiste:

var foo = {
    a: function(){return 5}(),
    b: function(){return 6}(),
    c: function(){return this.a + this.b}
}

console.log(foo.c())

Auch hier gibt es bessere Antworten . Dies ist, wie ich geändert Beispielcode Sie mit in Frage gestellt.

UPDATE:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);

7voto

Rafael Rocha Punkte 716

Sie können dies mit dem Modulmuster tun. Einfach so:

var foo = function() {
  var that = {};

  that.a = 7;
  that.b = 6;

  that.c = function() {
    return that.a + that.b;
  }

  return that;
};
var fooObject = foo();
fooObject.c(); //13

Mit diesem Muster können Sie je nach Bedarf mehrere foo-Objekte instanziieren.

http://jsfiddle.net/jPNxY/1/

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X