Zugriff auf Variablen von anderen Funktionen ohne Verwendung globaler Variablen

71

Ich habe von verschiedenen Orten gehört, dass globale Variablen von Natur aus böse und böse sind, aber wenn ich nicht objektorientiertes Javascript mache, kann ich nicht sehen, wie ich sie vermeiden kann. Angenommen, ich habe eine Funktion, die eine Zahl mithilfe eines komplexen Algorithmus unter Verwendung von Zufallszahlen und Ähnlichem generiert, aber ich muss diese bestimmte Zahl weiterhin in einer anderen Funktion verwenden, die ein Rückruf oder etwas anderes ist und daher nicht Teil derselben Funktion sein kann.

Wenn die ursprünglich generierte Nummer eine lokale Variable ist, kann von dort aus nicht darauf zugegriffen werden. Wenn die Funktionen Objektmethoden wären, könnte ich die Zahl zu einer Eigenschaft machen, aber das ist nicht der Fall, und es scheint etwas zu kompliziert, die gesamte Programmstruktur zu ändern, um dies zu tun. Ist eine globale Variable wirklich so schlecht?

Andreas Grech
quelle
6
@annakata becuase gibt es schon einige hochnäsig Benutzer auf SO
vimes1984

Antworten:

56

Um eine in Funktion A berechnete Variable in Funktion B sichtbar zu machen, haben Sie drei Möglichkeiten:

  • mach es zu einem globalen,
  • machen Sie es zu einer Objekteigenschaft, oder
  • Übergeben Sie es als Parameter, wenn Sie B von A aus aufrufen.

Wenn Ihr Programm ziemlich klein ist, sind Globals nicht so schlecht. Andernfalls würde ich die dritte Methode in Betracht ziehen:

function A()
{
    var rand_num = calculate_random_number();
    B(rand_num);
}

function B(r)
{
    use_rand_num(r);
}
Paul Stephenson
quelle
4
verschmutzen Sie nicht den globalen Namespace! Ihr Worst-Case-Fallback sollte nicht mehr sein als das Erstellen einer Objekteigenschaft mit einem einzelnen benutzerdefinierten globalen Objekt
annakata
Eine vierte Option, die ich mir ausgedacht habe, als alle drei für mich nicht funktionierten. stackoverflow.com/questions/3531080/… (siehe Antwort von Emile)
Kyle
ps. Uhr auf dem Link oben, suchen Sie nach einer ungeprüften Antwort von "Emile"
Kyle
Ich verstehe, dass dies ziemlich alt ist, aber ich habe mich nur gefragt, ob eine umfassende Verwendung der dritten Methode in einem großen Programm nicht zu Spaghetti-Code führen würde.
Aryan Poonacha
Das ist also Curry? Ich habe eine Weile versucht, mich darum zu
kümmern,
81

Ich denke, Ihre beste Wahl hier ist es, eine einzelne Variable mit globalem Gültigkeitsbereich zu definieren und Ihre Variablen dort abzulegen:

var MyApp = {}; // Globally scoped object

function foo(){
    MyApp.color = 'green';
}

function bar(){
    alert(MyApp.color); // Alerts 'green'
} 

Niemand sollte dich anschreien, weil du so etwas getan hast.

Triptychon
quelle
Das Problem mit Ihrem Beispiel ist, dass es länger dauert, bis Javascript verschachtelte Objekte verarbeitet. (Dies würde lange dauern:MyApp.something.color.somethingElse
Progo
20
Progo, das ist kein wirkliches Problem.
Triptychon
6
Die Funktion var()sollte geändert werden in bar(), dieser winzige Syntaxfehler könnte jemandem in der Zukunft Kopfschmerzen bereiten.
Harrypujols
1
Danke, genau das, was ich brauchte! Aber ich verstehe nicht, wie MyApp.colorsoll erstellt und bevölkert werden, wenn foo()es nie aufgerufen wird?
Chazy Chaz
Triptychon, danke, dass Sie zu meiner Arbeitsplatzsicherheit beigetragen haben: p
Jean-Michaël Celerier
15

Erwägen Sie die Verwendung von Namespaces:

(function() {
    var local_var = 'foo';
    global_var = 'bar'; // this.global_var and window.global_var also work

    function local_function() {}
    global_function = function() {};
})();

Beide local_functionund global_functionhaben Zugriff auf alle lokalen und globalen Variablen.

Bearbeiten : Ein weiteres gängiges Muster:

var ns = (function() {
    // local stuff
    function foo() {}
    function bar() {}
    function baz() {} // this one stays invisible

    // stuff visible in namespace object
    return {
        foo : foo,
        bar : bar
    };
})();

Auf die returned-Eigenschaften kann jetzt über das Namespace-Objekt zugegriffen werden, z. B. ns.foounter Beibehaltung des Zugriffs auf lokale Definitionen.

Christoph
quelle
super tolle Antwort! Endlich eine klassenähnliche Struktur wie in einer anderen Sprache :)
Dadan
Das ist großartig, dies sollte die akzeptierte Antwort sein. Das zweite Muster wird anscheinend als "statischer Namespace mit dem
Objektmuster
8

Was Sie suchen, ist technisch als Currying bekannt.

function getMyCallback(randomValue)
{
    return function(otherParam)
    {
        return randomValue * otherParam //or whatever it is you are doing.
    }

}

var myCallback = getMyCallBack(getRand())

alert(myCallBack(1));
alert(myCallBack(2));

Das Obige ist nicht gerade eine Curry-Funktion, aber es erzielt das Ergebnis, einen vorhandenen Wert beizubehalten, ohne Variablen zum globalen Namespace hinzuzufügen oder ein anderes Objekt-Repository dafür zu benötigen.

AnthonyWJones
quelle
-1. Dies ist nicht nur kein Beispiel für Curry, es ist auch eine viel zu komplizierte Antwort auf das Problem.
Triptychon
5
@triptych: Ich bin anderer Meinung. Dies ist eine absolut gültige und interessante Lösung für diese Art von Problem und genau das Currying ( Dustindiaz.com/javascript-curry )
Annakata
+1 verwirrend ... dann aufschlussreich! Einmal habe ich klar gesehen, dass dies myCallbackein Verweis auf die Funktion ist, getMyCallbackdie mit dem randomValuebereits eingestellten zurückkehrt. Die Verwendung von getRandist auch lehrreich, da ich sehe, dass ein mehrfacher myCallBack(1)Aufruf denselben Wert myCallbackzurückgibt, also dem entspricht, von dem zurückgegeben wird, getMyCallBack(getRand())und nicht nur ein Verweis auf die Funktion selbst ist. Es hat geholfen, es nur laut
auszusprechen
5

Ich fand dies in Bezug auf die ursprüngliche Frage äußerst hilfreich:

Geben Sie den Wert zurück, den Sie in functionOne verwenden möchten, rufen Sie functionOne in functionTwo auf, platzieren Sie das Ergebnis in einer neuen Variablen und verweisen Sie auf diese neue Variable in functionTwo. Dies sollte es Ihnen ermöglichen, die in functionOne deklarierte Variable in functionTwo zu verwenden.

function functionOne() {
  var variableThree = 3;
  return variableThree;
}

function functionTwo() {
  var variableOne = 1;
  var var3 = functionOne();

  var result = var3 - variableOne;

  console.log(variableOne);
  console.log(var3);
  console.log('functional result: ' + result);
}

functionTwo();
gav_aus_web
quelle
4

Wenn eine andere Funktion eine Variable verwenden muss, übergeben Sie sie als Argument an die Funktion.

Auch globale Variablen sind nicht von Natur aus böse und böse. Solange sie richtig verwendet werden, gibt es kein Problem mit ihnen.

Adam Peck
quelle
2
Globale Variablen sind in Javascript extrem böse. -1.
Triptychon
2

Wenn die Möglichkeit besteht, dass Sie diesen Code wiederverwenden, würde ich mich wahrscheinlich bemühen, eine objektorientierte Perspektive zu wählen. Die Verwendung des globalen Namespace kann gefährlich sein - Sie laufen Gefahr, aufgrund von Variablennamen, die wiederverwendet werden, schwer zu findende Fehler zu finden. Normalerweise verwende ich zunächst einen objektorientierten Ansatz für mehr als einen einfachen Rückruf, damit ich nicht neu schreiben muss. Jedes Mal, wenn Sie eine Gruppe verwandter Funktionen in Javascript haben, ist dies meiner Meinung nach ein Kandidat für einen objektorientierten Ansatz.

Tvanfosson
quelle
2

Ein anderer Ansatz ist einer, den ich in einem Forumsbeitrag von Douglas Crockford ( http://bytes.com/topic/javascript/answers/512361-array-objects ) aufgegriffen habe . Hier ist es...

Douglas Crockford schrieb:

15. Juli 2006

"Wenn Sie Objekte anhand ihrer ID abrufen möchten, sollten Sie ein Objekt und kein Array verwenden. Da Funktionen auch Objekte sind, können Sie die Elemente in der Funktion selbst speichern."

function objFacility(id, name, adr, city, state, zip) {

    return objFacility[id] = {

        id: id,
        name: name,
        adr: adr,
        city: city,
        state: state,
        zip: zip

    }
}

objFacility('wlevine', 'Levine', '23 Skid Row', 'Springfield', 'Il', 10010);

"Das Objekt kann mit erhalten werden"

objFacility.wlevine

Auf die Objekteigenschaften kann jetzt von jeder anderen Funktion aus zugegriffen werden.

Joel Erenberg
quelle
1

Ich kenne keine Einzelheiten zu Ihrem Problem, aber wenn die Funktion den Wert benötigt, kann es sich um einen Parameter handeln, der durch den Aufruf übergeben wird.

Globale Werte werden als schlecht angesehen, da der globale Status und mehrere Modifikatoren schwer zu befolgenden Code und seltsame Fehler verursachen können. Für viele Schauspieler kann das Herumspielen an etwas Chaos verursachen.

Arthur Thomas
quelle
1

Sie können die Ausführung von Javascript-Funktionen vollständig steuern (und Variablen zwischen ihnen übergeben), indem Sie benutzerdefinierte jQuery-Ereignisse verwenden. Mir wurde gesagt, dass dies in diesen Foren nicht möglich ist, aber ich habe etwas zum Laufen gebracht, das genau das tut (sogar mit ein Ajax-Anruf).

Hier ist die Antwort (WICHTIG: Es ist nicht die überprüfte Antwort, sondern die Antwort von mir "Emile"):

So erhalten Sie eine Variable, die über mehrere Funktionen zurückgegeben wird - Javascript / jQuery

Kyle
quelle