2012-03-27 14 views
7

W JavaScript można przepisać funkcji, tak jak poniżej:Konsekwencje Dynamiczne przepisywanie funkcji w javascript?

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

Oczywiście jest to wymyślony przykład, ale czy jest coś złego w tym koncepcyjnym podejściu ( innego niż wyścigu ).

+2

Dlaczego wystąpiłby stan wyścigu? W JavaScript nie ma wielu jednoczesnych wątków. – mellamokb

+0

Oh duh. Dzięki :) – Alan

Odpowiedz

7

Kod samoczynnie modyfikujący może być mylący i trudny do debugowania, więc jest generalnie unikany.

Poza tym nie ma problemu, a także brak wyścigu.

+2

To nie jest samodyfikujący się kod. Robi dobrze zdefiniowaną rzecz: zastępuje wiążące 'foo', które posiada funkcję, z nową funkcją. – Kaz

+0

tj. dla jasności: oryginalna funkcja nie ulega destruktywnej zmianie na inną funkcję; tylko utrata odniesienia do tej funkcji jest bardzo różna. Modyfikowanie środowiska wiążącego zmienne nie jest tym samym, co modyfikowanie kodu w miejscu. – Kaz

+0

@Kaz: Tak, to nie jest samoczynne modyfikowanie, ale efekt jest taki sam, więc może być równie trudne do naśladowania. Jeśli chcesz zmienić funkcję, powinieneś zadeklarować ją jako zmienną od początku, jeśli deklarowana jest za pomocą zwykłej składni funkcji, zazwyczaj nie oczekuje się zmiany. – Guffa

4

Jedna rzecz, którą zauważyłem podczas testowania twojego kodu. Rozważ to:

setInterval(foo, 6000); 

Funkcja foo jest przekazywany do setInterval zanim został zmodyfikowany, a oryginalnyfoo potrwa co 6 sekund, nawet po związaniu został zaktualizowany.

Z drugiej strony poniższy kod uruchomi oryginalną funkcję tylko przy pierwszym wywołaniu (które aktualizuje wiązanie). Kolejne połączenia będą powoływać zaktualizowaną wersję:

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

Wygląda oczywiste, ale może być trudne do debugowania ...

3

Dynamiczna funkcja przepisywania może być stosowany jako forma lazy initialization, jednak jest pewien haczyk:

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); 
    } 
}; 

Podczas gdy ten kod jest stosunkowo prosta do zrozumienia, i będą wykorzystywane jako:

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

ma ukryty problem:

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 

To z tego powodu, że każdy inicjalizacji potrzebne do funkcji jest zazwyczaj odbywa się za pomocą wzoru modułu:

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; 
    }()) 
}; 

Wzór moduł ma tę wadę, nazywając kod inicjujący natychmiast, ale nie będzie miał problemów związanych z odwołaniem do funkcji.

Powiązane problemy