Da ich ziemlich neu in Javascript bin und einen C # -Hintergrund habe, bin ich angemessen mitgestolpert. Ich wusste, dass ich mich früh genug mit der Tatsache auseinandersetzen musste, dass Funktionen eigenständige Objekte sind und dass JS-Verschlüsse häufig zu Verwirrung führen.

Ich versuche, diesen kleinen Codeausschnitt zu verstehen

// Function which returns object with function properties
function myFunc() {

    value = 42;

    var result = {
        value: value,
        getValue: getValue,
        incrementValue: incrementValue,
        setValue: setValue,
    };
    return result; 

    function setValue(y) {
        value = y;
    };

    function getValue() {
         return value;   
    }; 

    function incrementValue() {
        value++;
    };
};

// Helper function to print out results
function printResults(m,x){
    $('#output').append(m + ': ' + x).append('<br/>');
};

var myObject = myFunc();  // returns the object 
printResults('Inital call to getValue',myObject.getValue());

myObject.setValue(59);
printResults('Called changeValue',myObject.getValue());

printResults('Value property of object',myObject.value);
printResults('Called getValue again',myObject.getValue());

myObject.incrementValue();
printResults('Call increment value',myObject.getValue());
printResults('Value property of object',myObject.value);

Ich erhalte die folgenden Ergebnisse, wenn ich in jsFiddle ausgeführt werde

Inital call to getValue: 42
Called changeValue: 59
Value property of object: 42
Called getValue again: 59
Call increment value: 60
Value property of object: 42

Diese zeigen, dass die Funktionen die Variable value in ihrem Abschluss verwenden und dies zwischen dem Aufruf der inneren Funktionen bestehen bleibt. ABER der Wert von value ändert sich im zurückgegebenen Objekt nicht.

Ich denke, ich verstehe den grundlegenden Punkt, dass Funktionen unter Verwendung der Bereichskette ausgeführt werden, die zum Zeitpunkt ihrer Definition gültig war.

Fragen Kann ich die value -Eigenschaft des zurückgegebenen Objekts auf dieselbe Weise ausführen lassen - oder ist dies die einzige Möglichkeit, sie über eine Funktion zurückzugeben, da diese die Variable beim Schließen beibehält?

Und , nur zur Bestätigung, für jeden Aufruf von myFunc() gehe ich davon aus, dass ich ein Objekt erhalte, dessen Funktionseigenschaften eine eigene Bereichskette haben und daher von jedem Aufruf unabhängig sind.

0
jcaddy 24 Nov. 2013 im 22:14

2 Antworten

Beste Antwort

Vergessen Sie beim Deklarieren von Variablen zunächst nicht das Schlüsselwort var. Wenn Sie value = 42 in myFunc deklarieren, erstellen Sie tatsächlich eine Variable im globalen Namespace anstelle des Funktionsumfangs. Es sollte so beginnen:

function myFunc() {
    var value = 42;

Jetzt gibt myObject.result 42 zurück, weil myFunc Ihr result Objekt zurückgibt, das eine Kopie der in der Funktion deklarierten Variablen value enthält.

Ihre Funktionen setValue, getValue und incrementValue ändern den Wert von value und nicht von result.value. Wenn Sie myObject.value aufrufen, erhalten Sie den Wert vom zurückgegebenen Objekt, nicht von der inneren Variablen Ihrer Funktion.

Sie könnten es mit so etwas zum Laufen bringen:

function myFunc() {
    var value = 42;
    var result = {
        value: value,
        getValue: getValue,
        incrementValue: incrementValue,
        setValue: setValue
    };

    return result;

    function setValue(y) {
        result.value = y;
    }

    function getValue() {
        return result.value;
    }

    function incrementValue() {
        result.value++;
    }
}

Es gibt jedoch bessere Entwurfsmuster als diese. Mit dem Schlüsselwort new und prototype können Sie die Methoden definieren, die für die von Ihrer Funktion zurückgegebenen Objekte verfügbar sind. Nehmen Sie dieses Beispiel:

function myFunc() {
    this.value = 42;
}

myFunc.prototype.setValue = function(y) {
    this.value = y;
}

myFunc.prototype.getValue = function(y) {
    return this.value;
}

myFunc.prototype.incrementValue = function(y) {
    this.value++;
}

var myObject = new myFunc();
console.log(myObject.getValue()); // 42
myObject.setValue(30);
myObject.incrementValue();
console.log(myObject.getValue()); // 31
5
Guilherme Sehn 24 Nov. 2013 im 18:33

Kann ich die value-Eigenschaft des zurückgegebenen Objekts auf die gleiche Weise ausführen lassen?

Wenn Sie meinen, dass der aktualisierte Wert angezeigt wird, können Sie dies tun. Sie müssen nur den Code ändern, um auch die Eigenschaft value zu aktualisieren:

function myFunc() {

    var value = 42; // don't forget var!

    var result = {
        value: value,
        getValue: getValue,
        incrementValue: incrementValue,
        setValue: setValue,
    };
    return result; 

    function setValue(y) {
        result.value = value = y;
    }

    function getValue() {
         return value;   
    }

    function incrementValue() {
        value++;
        result.value = value;
    }
}

Der Grund, warum ich sowohl value als auch result.value verwende, besteht darin, die Änderung des Werts durch result.value zu verhindern. Wenn Sie bemerken, lese ich nicht intern von aus result.value, sondern schreibe nur darauf. Das bedeutet, dass Zuweisungen von {externem Code zu result.value keine Auswirkung haben. Dies entspricht der Funktionsweise Ihres vorhandenen Codes.

Und nur zur Bestätigung gehe ich davon aus, dass ich für jeden Aufruf von myFunc() ein Objekt erhalte, dessen Funktionseigenschaften eine eigene Gültigkeitsbereichskette haben und daher von jedem Aufruf unabhängig sind.

Ja, jeder Aufruf von myFunc erstellt ein neues Objekt und neue Funktionen und sie sind völlig unabhängig von Objekten / Funktionen, die durch vorherige Aufrufe erstellt wurden.

1
Felix Kling 24 Nov. 2013 im 19:30