2013-07-03 17 views
13

Ich versuche, ein tieferes Verständnis zu gewinnen, wie Javascript funktioniert und der folgende Code nervt mich:Warum verschwindet der Funktionsname, wenn er einer Variablen zugewiesen ist?

function notInVar(a, b) { 
    return a + b 
} 

var inVar = function doesThisWork(a, b) { 
    return a + b 
} 

document.writeln('2 + 2 = ' + notInVar(2, 2)); 
document.writeln('3 + 3 = ' + inVar(3, 3)); 
document.writeln('4 + 4 = ' + doesThisWork(4, 4)); 

In Chrome, die ersten beiden document.writelns wie erwartet ausführen, dann bekomme ich "Uncaught ReferenceError: doesThisWork is not defined" in Chrome. Warum kann ich die zweite Funktion nicht mit dem Namen doesThisWork aufrufen? Wo wird das erste Funktionsobjekt notInVar gespeichert?

+2

@stackErr: Scheint gut. Das ist ein benannter Funktionsausdruck. – elclanrs

+0

nicht sicher, aber ich würde sagen, variabler Bereich. –

+1

[Dies scheint nützlich zu sein] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression). – Marty

Antwort

5

Funktionen sind Objekte. Die Variable inVar enthält ein Funktionsobjekt mit dem Namen doesThisWork.

inVar.name //=> "doesThisWork" 

Wenn eine Funktion keinen Namen hat, ist sie anonym.

Um eine in einer Variablen gespeicherte Funktion aufzurufen, verwenden Sie den Variablennamen (die Referenz auf dieses Objekt). Wenn Sie die Funktion innerhalb derselben Funktion (für Rekursion) aufrufen möchten, können Sie sie mit ihrem Namen aufrufen, in diesem Fall doesThisWork.

+0

Danke für die Erklärung, wo der Funktionsname gelandet ist. –

4

For that matter, where is the first function-object notInVar stored?

function notInVar(a, b) { 
    return a + b 
} 

äquivalent zu

var notInVar = function (a, b) { 
     return a + b 
} 

In Ihrem Fall ist notInVar im globalen Bereich gespeichert.

then I get "Uncaught ReferenceError: doesThisWork is not defined" in Chrome

var inVar = function doesThisWork(a, b) { 
    return a + b 
} 

Ist ähnlich wie

var inVar = function (a, b) { 
     return a + b 
    } 

, wenn es außerhalb zugegriffen wird die Funktion

Sie nicht die Funktion von doesThisWork zugreifen können, aber müssen es inVar durch Zugriff

+1

Nicht ganz ... Das nächste Äquivalent wäre 'var foo = function foo() {}', so haben Sie immer noch einen 'name', der in der Call-Stack-Trace angezeigt werden kann. – elclanrs

+0

Siehe Schnelltest hier http://jsbin.com/onewoh/1/edit – elclanrs

+0

@elclanrs: Ich denke, ich muss das umschreiben. Es ist ** ähnlich ** wenn es ** außerhalb ** der Funktion aufgerufen wird. Danke für das Aufzeigen, jeder Weg –

1

Die Art, wie Sie es geschrieben haben, doesThisWork ist nur in sich selbst verfügbar.

8

ist die zweite Definition eines named function expression und aufgrund der Art dieser Definition ist die einzige Möglichkeit genannt Sie es nach Name ist von innerhalb der Funktionskörper anrufen: zu

var inVar = function doesThisWork(a, b) { 
    return doesThisWork(a + b); // infinite recursion! 
} 

Dieses verwendet werden kann Rekursion innerhalb einer ansonsten anonymen Funktion erreichen, ohne etwas wie die Y-combinator verwenden zu müssen.

+0

Wie verhält es sich mit dem Y-Combinator? Dies wird dich nicht unendliche Rekursion wie der Y-Combinator machen lassen, wenn du das vorschlägst. –

+0

@CrazyTrain Der Y-Kombinator bewirkt eine anonyme Rekursion; und unendliche Rekursion ist immer möglich :) –

+0

Mit dem Y-Combinator können Sie unendliche Rekursion haben, weil der Call-Stack nicht wächst. Wenn Sie der Funktion einen Namen geben, wird der Anruf-Stack nicht beeinträchtigt. Und JavaScript-Funktionen sind nicht Tail-Call-optimiert. –

0

Funktion ist eine Variable und der Umfang der Variablen ist wichtig. Für die zweite Funktion im globalen Gültigkeitsbereich lautet der Variablenname inVar. Der Funktionsname doesThisWork befindet sich in einem eigenen Bereich und ist für den globalen Bereich nicht sichtbar. Sie können also nur InVar verwenden, nicht DoThisWork.

0

gut es gibt mehrere Dinge dazu:

zuerst: Der Name der Funktion wird lokal sein, so dass Sie in nur lokal die gleiche Funktion aus aufrufen können. Das kann bei Verwendung eine unendliche Rekursion auslösen, es sei denn, es wird so gefiltert if(doesThisWork.caller != doesThisWork) return doesThisWork(a,b);.

Zweitens weisen Sie der Funktion einen Namen zu (nicht als anonyme Funktion), sondern lokal für den Container.

TL; DR => springen Sie zu der Analyse für eine klarere Idee.

ist es interessant, die Unterschiede beachten zwischen Deklaration Methoden der Funktion:

Inline-Deklaration:

var x = function fnName(){}; console.log(x.prototype); => fnName {} // but used locally to x 
var x = function(){}; console.log(x.prototype); => Object {} // no local name, only global x 

bei Parse Zeit/Laufzeit Erklärung:

function fnName(){}; console.log(fnName.prototype); => fnName {} // global* and local name 

Meine Analyse: ist, dass die Lokalität hier aufgrund der Zuweisung ist, wie wenn Sie eine Funktion innerhalb der Funktion deklarieren, wird dieser Name lokal zu der enthaltenden Funktion und nicht außerhalb verwendet, das gleiche gilt für die Variable, die eine Funktion enthält, denn es enthält es und seinen Namen. immer noch kann die Variable, die die Funktion enthält, in ihrem Gültigkeitsbereich verwendet werden, da sie lokal für ihre Container-Funktion ist, die ein anderer Bereich ist.

* global bedeutet hier global zum Speicherort der Funktion nicht zum Dokument. da es lokal für den Container, aber global für andere Objekte im selben Container ist.

Verwandte Themen