2012-03-27 16 views
7

in JavaScript, è possibile riscrivere una funzione, in questo modo:Conseguenze di riscrivere dinamicamente una funzione in javascript?

function foo() { 
    setTimeout(function() { 
     alert('sup stallion'); 
     foo = function() { //rewrite foo to nolonger wait 4 seconds to alert. 
      alert('sup stallion'); 
     } 
    }, 4000); 
} 

Ovviamente questo è un esempio forzato, ma c'è qualcosa di concettualmente sbagliato in questo approccio ( diverso da una condizione di competizione ).

+2

Perché ci dovrebbe essere una condizione di gara? Non ci sono più thread simultanei che eseguono JavaScript. – mellamokb

+0

Oh duh. Grazie :) – Alan

risposta

7

Il codice di auto modifica può essere confuso e difficile da eseguire il debug, quindi è generalmente evitato.

A parte questo non ci sono problemi e nemmeno le condizioni di gara.

+2

Questo non è un codice auto-modificante. Sta facendo una cosa ben definita: sostituendo il "pippo" vincolante che contiene una funzione, con una nuova funzione. – Kaz

+0

I.e. per essere più chiari: la funzione originale non viene modificata in modo distruttivo in un'altra funzione; si sta perdendo solo un riferimento a quella funzione, che è molto diversa. La modifica dell'ambiente di binding variabile non equivale alla modifica del codice in atto. – Kaz

+0

@Kaz: Sì, non è strettamente modificabile, ma l'effetto è lo stesso, quindi può essere altrettanto difficile da seguire. Se vuoi cambiare la funzione dovresti dichiararla come variabile dall'inizio, se è dichiarata usando la sintassi della funzione normale in genere non è previsto che cambi. – Guffa

4

Una cosa che ho notato durante il test del codice. Considerate questo:

setInterval(foo, 6000); 

Funzione foo viene passato al setInterval prima che fosse modificata, e il originalefoo verrà eseguito ogni 6 secondi, anche dopo che il legame è stato aggiornato.

D'altra parte, il codice seguente eseguirà la funzione originale solo alla prima chiamata (che aggiorna l'associazione). Le chiamate successive invocheranno la versione aggiornata:

setInterval(function(){foo();}, 6000); 

Sembra ovvio, ma potrebbe essere difficile da eseguire il debug ...

3

funzione dinamica riscrittura può essere usato come una forma di lazy initialization, tuttavia c'è un problema:

function Foo() {...} 
Foo.prototype = { 
    bar: function() { 
     //some initialized variables to close over 
     var a, b, c, ...; 
     Foo.prototype.bar = function() { 
      //do stuff with variables 
     }; 
     Foo.prototype.bar.call(this); 
    } 
}; 

Anche se questo codice è relativamente straight-forward per capire, e sarebbe stato utilizzato come:

var f = new Foo(); 
f.bar(); //initializes `bar` function 
f.bar(); //uses initialized `bar` function 

ha un problema nascosto:

var f = new Foo(), 
    g = {}; 
//passing by reference before the function was initialized will behave poorly 
g.bar = f.bar; 
f.bar(); //initializes `bar` function 
g.bar(); //re-initializes `bar` function 
f.bar(); //uses initialized `bar` function 
g.bar(); //re-initializes `bar` function 

E 'per questo motivo che ogni inizializzazione necessario per una funzione è in genere fatto utilizzando un modello di modulo:

function Foo() {...} 
Foo.prototype = { 
    bar: (function() { 
     var a, b, c, ..., fn; 
     //some initialized variables to close over 
     fn = function() { 
      //do stuff with variables 
     }; 
     return fn; 
    }()) 
}; 

Il modello modulo ha lo svantaggio di chiamare il codice di inizializzazione immediatamente, ma non avrà i problemi associati al riferimento alla funzione.

Problemi correlati