2012-03-30 22 views
5

Si consideri il codice:Perché Javascript non consente a una funzione di ridefinire se stessa da se stessa?

window.a = function(x){ 
     var r = x*2; 
     window.a =alert; // redefines itself after first call 
     return r; 
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4" 

Questo non funziona neanche:

window.a = function(x){ 
     alert(x); 
     window.a = function(x){ // redefines itself after first call 
      var r = x*2; 
      return r; 
     } 
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4" 

Come nessuno fa questo:

window.a = function(x){ alert(x); window.c = window.a; window.a = window.b; window.b = window.c; }; 
    window.b = function(x){ var r = x*2; window.c = window.b; window.b = window.a; window.a = window.c; return r; }; 
    a('2 * 2 = '+a(2)); // doesn't work. 

E in fondo ho provato tutti i modi possibili e nessuno dei due sembra fare il lavoro. Qualcuno può spiegare perché?

+1

solo per curiosità, perché stai provando a fare questo? – maialithar

+0

Bene, il primo in realtà funziona per me (Chrome 18) – Yoshi

+0

Funziona perfettamente in Chrome e IE ... –

risposta

8

È sono ridefinire con successo la funzione, è solo che l'espressione definendolo ha già afferrato il vecchio riferimento di funzione: La prima cosa che succede in un'espressione chiamata è che la cosa definire quale funzione chiamare viene valutata, vedi Section 11.2.3 del disciplinare:

11.2.3 funzione chiama

la produzione CallExpression: Argomenti MemberExpression viene valutata una s segue:

  1. Let ref essere il risultato della valutazione MemberExpression.
  2. Lasciate func be GetValue (rif).
  3. Lasciate arg.List essere il risultato della valutazione di Argomenti, producendo un elenco interno di valori di argomento (vedere 11.2.4).
  4. Se Type (func) non è Object, genera un'eccezione TypeError.
  5. Se IsCallable (func) è false, genera un'eccezione TypeError.
  6. Se Tipo (ref) è di riferimento, quindi
        a) Se IsPropertyReference (ref) è vera, allora
                i. Let thisValue be GetBase (rif).
        b) Altrimenti, la base di ref è un record Ambiente
                i. Let thisValue essere il risultato di chiamare il metodo concreto ImplicitThisValue di GetBase (rif).
  7. Altro, tipo (rif) non è un riferimento.
    a) Lasciare questo valore essere indefinito.
  8. ritorno il risultato della chiamata al metodo interno [[Bando]] sulla func, fornendo ThisValue come tale valore e di fornire l'elenco arglist come i valori degli argomenti.

I passaggi 1 e 2 si verificano prima che la funzione venga ridefinita.

La soluzione è ovviamente quello di far accadere le cose nell'ordine che ci si aspetta (live example | source):

window.a = function(x){ 
    var r = x*2; 
    window.a =alert; // redefines itself after first call 
    return r; 
}; 
var val = a(2); 
a('2 * 2 = '+ val); 

Nota a margine: E 'interessante che your first example opere in Chrome (V8) (anche funziona nella versione di JScript di IE6, ma poi, JScript aveva lotti di problemi). Non dovrebbe funzionare, e non in Firefox (SpiderMonkey), Opera (Carakan) o IE9 (Chakra).

1

JavaScript ha una rigida regola da sinistra a destra per l'ordine di valutazione degli argomenti dell'operatore. Immagino che questo includa l'operatore di chiamata di funzione, il che significa che il primo a viene valutato prima dell'espressione.