2010-10-26 39 views
5

Hãy nói rằng tôi có hai chức năng:javascript: Re-gán một chức năng với chức năng khác

function fnChanger(fn) { 
    fn = function() { sys.print('Changed!'); } 
} 
function foo() { 
    sys.print('Unchanged'); 
} 

Bây giờ, nếu tôi gọi foo(), tôi thấy Unchanged, như mong đợi. Tuy nhiên, nếu tôi gọi fnChanger đầu tiên, tôi vẫn thấy Unchanged:

fnChanger(foo); 
foo(); //Unchanged 

Bây giờ, tôi giả định này là bởi vì foo không được truyền cho fnChanger bằng cách tham khảo, nhưng tôi có thể sai.

Tại sao fnChanger không thay đổi foo để in Changed!?
Hơn nữa, làm cách nào tôi có thể nhận được fnChanger để thay đổi foo mà không có quá nhiều cú pháp lộn xộn?

PS: Tôi đang sử dụng node.js để kiểm tra tất cả nội dung này, vì vậy đó là nơi số sys.print xuất phát từ đó.

Trả lời

5

Việc gán cho đối số fn chỉ làm cho số nhận dạng đó trỏ đến hàm ẩn danh, foo trong phạm vi bên ngoài không bị ảnh hưởng.

Khi bạn chuyển đối tượng làm đối số, người ta có thể nói "tham chiếu được chuyển bởi giá trị". Bài tập chỉ thay thế vị trí mà số nhận dạng fn đề cập đến.

Đó là cách hoạt động của JavaScript trong evaluation strategy.

Ngay trước khi sự phân công trong fnChanger chức năng, hai định danh, toàn cầu foofn cãi nhau, điểm đến đối tượng chức năng tương tự:

 
       --------------------------------------------- 
    foo -----> |function foo { sys.print('Un changed!'); } | 
       --------------------------------------------- 
       ^
        | 
    fn ------------- 

Sau khi chuyển nhượng, fn sẽ chỉ đơn giản là trỏ đến mới chức năng:

 
       --------------------------------------------- 
    foo -----> | function foo { sys.print('Unchanged!'); } | 
       --------------------------------------------- 

       --------------------------------------- 
    fn ------> | function { sys.print('Changed!'); } | 
       --------------------------------------- 

Làm cách nào bạn có thể thay đổi?

Vâng, giả định rằng foo là một chức năng trong phạm vi toàn cầu, bạn có thể làm một cái gì đó như thế này:

function fnChanger(obj, name) { 
    obj[name] = function() { sys.print('Changed!'); }; 
} 

function foo() { 
    sys.print('Unchanged'); 
} 

fnChanger(this, 'foo'); 
foo(); // Changed! 

trên sẽ làm việc vì trong fnChanger chức năng, chúng tôi yêu cầu một đối tượng cơ sở và một Tên thuộc tính, các hàm được khai báo trong ngữ cảnh thực thi chung được ràng buộc là thuộc tính của đối tượng Toàn cầu , do đó chúng tôi có thể gán lại giá trị của nó theo cách đó.

Dòng fnChanger(this, 'foo'); nên được thực hiện cũng trong phạm vi toàn cầu, nó sẽ vượt qua giá trị this (trong đó đề cập đến đối tượng toàn cầu trong phạm vi này) và một tên thuộc tính, cho phép bạn thực hiện một nhiệm vụ để nhận dạng GlobalObject.foo.

Nếu mã mà là bên trong một hàm, không có cách nào chúng ta có thể có được một đối tượng cơ sở, bởi vì trong này "Mã hàm Execution Context", tờ khai chức năng (khai báo biến và chức năng các thông số chính thức cũng) đang bị ràng buộc như tài sản đối tượng không thể truy cập, được gọi là Đối tượng biến (một chuỗi các đối tượng biến đổi này, tạo thành Chuỗi phạm vi) và nếu đúng như vậy, cách giải quyết duy nhất sẽ là sử dụng eval. Thông tin

thêm:

+0

Yeah, tôi đã bắt đầu nghi ngờ đó là những gì đang xảy ra. Cảm ơn bạn đã làm rõ, và liên kết - Tôi không bao giờ biết chính xác những gì để gọi đó hoặc cách nó hoạt động. Làm sao để tôi có được xung quanh này? –

+0

Ok, tôi thích cách tiếp cận đó. Không phải là lộn xộn như tôi đã nghĩ đến việc làm: đi qua một đối tượng có chứa chức năng được thay đổi. –

2

Như @CMS chỉ ra bạn không thể gán nó bên trong hàm do phạm vi. Tuy nhiên bạn có thể chuyển nhượng lại như thế này:

var fnChanger = function() { 
    return function() { 
     alert('changed!'); 
    } 
} 

var foo = function() { 
    alert('Unchanged'); 
} 

foo = fnChanger(); 
foo(); 

example

+0

Vâng, hãy nghĩ về điều đó. Tôi do dự để làm điều đó bằng cách trở lại trong mã thực sự, mặc dù. Một mặt, nó sạch hơn, nhưng mặt khác, nó không hoàn toàn phù hợp với chức năng của nó. –

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