2013-07-03 11 views
13

Sto cercando di acquisire una più profonda comprensione di come funziona Javascript e il seguente codice mi sta intercettazioni:Perché il nome della funzione scompare quando viene assegnato a una var?

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, i primi due document.writelns eseguire come previsto, allora ottengo "Uncaught ReferenceError: doesThisWork is not defined" in Chrome. Perché non riesco a chiamare la seconda funzione con il nome doesThisWork? Del resto, dov'è il primo oggetto-funzione notInVar memorizzato?

+2

@stackErr: sembra soddisfacente. Questa è un'espressione di funzione con nome. – elclanrs

+0

non sono sicuro, ma direi scope variabile. –

+1

[Questo sembra utile] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope#Function_constructor_vs._function_declaration_vs._function_expression). – Marty

risposta

5

Le funzioni sono oggetti. La variabile inVar contiene un oggetto funzione con un nome di doesThisWork.

inVar.name //=> "doesThisWork" 

Se una funzione non ha nome, è anonima.

Per chiamare una funzione memorizzata in una variabile si utilizza il nome della variabile (il riferimento a tale oggetto). Se vuoi chiamare la funzione all'interno della stessa funzione (per la ricorsione) puoi chiamarla con il suo nome, in questo caso doesThisWork.

+0

Grazie per aver spiegato "dove è andato il nome della funzione". –

4

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

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

equivale a

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

Nel tuo caso, notInVar viene memorizzato nella portata globale.

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

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

è simile a

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

quando è letta di fuori la funzione

Non è possibile accedere alla funzione da doesThisWork, ma devono accedervi inVar

+1

Non proprio ... L'equivalente più vicino sarebbe 'var foo = function foo() {}', in questo modo si ha ancora un 'name' che può essere visualizzato nella traccia dello stack delle chiamate. – elclanrs

+0

Vedere test rapido qui http://jsbin.com/onewoh/1/edit – elclanrs

+0

@elclanrs: Penso di aver bisogno di riformularlo. È ** simile ** a quando si accede ** al di fuori ** della funzione. Grazie per aver segnalato, in qualsiasi modo, –

1

Il modo in cui lo hai scritto, doesThisWork è disponibile solo all'interno di se stesso.

8

La seconda definizione è chiamato un named function expression ed a causa della natura di tale definizione, l'unico modo in cui si può chiamare per nome è da all'interno il corpo della funzione:

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

Questo può essere usato per ottenere la ricorsione all'interno di una funzione altrimenti anonima, senza dover utilizzare qualcosa come lo Y-combinator.

+0

In che modo si riferisce a Y-Combinator? Questo non ti consentirà di fare una ricorsione infinita come farà Y-Combinator se è questo che stai suggerendo. –

+0

@CrazyTrain Il combinatore Y effettua una ricorsione anonima; e la ricorsione infinita è sempre possibile :) –

+0

Con l'Y-Combinator, puoi avere una ricorsione infinita perché lo stack di chiamate non cresce. Assegnare un nome alla funzione non impedisce la crescita dello stack di chiamate. E le funzioni JavaScript non sono ottimizzate per la coda. –

0

La funzione è una variabile e l'ambito della variabile è importante. Per la seconda funzione, nell'ambito globale, il nome della variabile è inVar. Il nome della funzione doesThisWork è all'interno del proprio ambito e non è visibile per l'ambito globale. Quindi puoi usare solo inVar, non in questoQuesto.

0

Beh, ci sono cose più su questo:

prima: il nome della funzione sarà locale, in modo da poter chiamare la stessa funzione dall'interno solo localmente. che potrebbe innescare una ricorsione infinita quando usato, a meno che non venga filtrato come questo if(doesThisWork.caller != doesThisWork) return doesThisWork(a,b);.

in secondo luogo è che si sta assegnando un nome per la funzione (non lo si lascia come funzione anonima) ma locale al suo contenitore.

TL; DR => passare all'analisi per un'idea più chiara.

è interessante notare le differenze tra i metodi di dichiarazione della funzione: dichiarazione

linea:

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 

al parse-time/dichiarazione di run-time:

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

La mia analisi: è che la località qui è dovuta all'assegnazione come quando si dichiara una funzione all'interno della funzione, quel nome sarà usato localmente per la funzione di contenimento e non al di fuori di questo, lo stesso vale per la variabile che contiene una funzione, dal momento che lo contiene ed è il suo nome. ancora la variabile che contiene la funzione può essere utilizzata nel suo ambito, in quanto è locale per la sua funzione contenitore che è un ambito diverso.

* globale qui significa globale alla posizione della funzione non al documento. come è locale al suo contenitore ma globale ad altri oggetti nello stesso contenitore.

Problemi correlati