2012-03-27 27 views
7

Trong javascript, bạn có thể viết lại một chức năng, như vậy:Hậu quả của việc tự động viết lại một hàm trong javascript?

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

Rõ ràng đây là một ví dụ giả tạo, nhưng là có bất cứ điều gì khái niệm sai với phương pháp này ( khác hơn là một tình trạng chủng tộc ).

+2

Tại sao sẽ có điều kiện chạy đua? Không có nhiều chuỗi đồng thời chạy JavaScript. – mellamokb

+0

Oh duh. Cảm ơn :) – Alan

Trả lời

7

Mã tự sửa đổi có thể gây nhầm lẫn và khó gỡ lỗi, vì vậy thường tránh được.

Khác với điều đó không có vấn đề gì và cũng không có điều kiện chủng tộc.

+2

Đây không phải là mã tự sửa đổi. Nó đang làm một điều được định nghĩa rõ ràng: thay thế 'foo' ràng buộc chứa một hàm, với một hàm mới. – Kaz

+0

I.e. rõ ràng hơn: chức năng ban đầu không bị thay đổi một cách triệt để thành một chức năng khác; chỉ một tham chiếu đến hàm đó đang bị mất, điều này rất khác. Sửa đổi môi trường ràng buộc biến không giống như sửa đổi mã tại chỗ. – Kaz

+0

@Kaz: Vâng, nó không phải là tự sửa đổi nghiêm ngặt, nhưng hiệu quả là như nhau, vì vậy nó có thể được chỉ là khó khăn để làm theo. Nếu bạn muốn thay đổi hàm, bạn nên khai báo nó như là một biến từ đầu, nếu nó được khai báo sử dụng cú pháp hàm thông thường, nó thường không được thay đổi. – Guffa

4

Một điều tôi đã nhận thấy khi kiểm tra mã của bạn. Xem xét việc này:

setInterval(foo, 6000); 

Chức năng foo đã được thông qua với setInterval trước khi nó được sửa đổi, và gốcfoo sẽ chạy mỗi 6 giây, ngay cả sau khi các ràng buộc đã được cập nhật.

Mặt khác, mã bên dưới sẽ chỉ chạy hàm ban đầu trong lần gọi đầu tiên (cập nhật liên kết). cuộc gọi tiếp theo sẽ gọi phiên bản cập nhật:

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

Trông rõ ràng, nhưng có thể là khó khăn để gỡ lỗi ...

3

chức năng động viết lại có thể được sử dụng như một hình thức lazy initialization, tuy nhiên có một nhược điểm:

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

Trong khi mã này là tương đối thẳng về phía trước để hiểu, và sẽ được sử dụng như:

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

nó có một vấn đề tiềm ẩn:

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 

Đó là vì lý do này mà bất kỳ khởi cần thiết cho một chức năng thường được thực hiện bằng cách sử dụng kiểu mô-đun:

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

Các mô hình mô-đun có những bất lợi của cách gọi mã khởi tạo ngay lập tức, nhưng sẽ không có các vấn đề liên quan đến tham chiếu hàm.

Các vấn đề liên quan