2010-04-12 39 views
18

Tôi đang nghe bài nói chuyện của Crockford về việc đóng JavaScript và bị thuyết phục vì lợi ích của việc ẩn thông tin, nhưng tôi không hiểu rõ về thời điểm sử dụng các chức năng gọi lại.Các trường hợp sử dụng cho các chức năng đóng/gọi lại trong JavaScript là gì?

Nó chủ yếu là một tuyên bố đúng rằng một người có thể thực hiện cùng chức năng có hoặc không có gọi lại.

Là người viết mã, tôi nên lưu ý những gợi ý hay gợi ý nào khi xác định thời điểm sử dụng gọi lại/đóng cửa?

Tôi không tìm kiếm tuyên bố về chăn 'Đóng cửa tạo mã an toàn hơn', thay vào đó là danh sách ví dụ thực tế hoặc quy tắc chung khi gọi lại là ý tưởng đúng.

Presentation Crockford: http://www.yuiblog.com/blog/2010/04/08/video-crockonjs-5/

Trả lời

29

Thứ nhất:

  • Gọi lại: Một hàm được chuyển như một đối số cho một hàm khác, thường được gọi là kết quả của một sự kiện xảy ra.
  • Đóng cửa: Phạm vi được giữ lại. I E. khái niệm khi bạn khai báo hàm trong hàm khác, phạm vi chức năng của bên ngoài có thể truy cập trong hàm bên trong.

Các cuộc gọi lại cũng có thể bị đóng, nhưng không phải lúc nào cũng vậy.

Đây là một callback:

someProcess(myCallback); 

function myCallback() { 
    alert('Done...'); 
} 

function someProcess(callback) { 
    // does stuff... 
    // ... 
    callback(); 
} 

Một đóng cửa:

function foo(msg) { 

    function bar() { 
     // I can access foo's scope 
     // (i.e. bar can access everything that foo can access) 
     alert(msg); 
    } 

    return bar; 

} 

foo('hello')(); // alerts "hello" 

Một sử dụng phổ biến của việc đóng cửa là cung cấp thông tin ẩn, đó là hữu ích trong việc đưa một số loại đóng gói với ngôn ngữ . Có một cái nhìn tại the module pattern để xem điều này trong hành động.

Một cách sử dụng phổ biến khác là khi xử lý sự kiện ràng buộc với các phần tử. Ví dụ.

var myElements = [ /* DOM Collection */ ]; 

for (var i = 0; i < 100; ++i) { 
    myElements[i].onclick = function() { 
     alert('You clicked on: ' + i); 
    }; 
} 

Điều đó sẽ không hiệu quả. Vào thời điểm phần tử được nhấp, biến số i99.Để làm công việc này đúng, chúng tôi lạnh sử dụng một đóng cửa để nắm bắt giá trị của i:

function getHandler(n) { 
    return function() { 
     alert('You clicked on: ' + n); 
    }; 
} 

for (var i = 0; i < 100; ++i) { 
    myElements[i].onclick = getHandler(i); 
} 
+0

ví dụ truy cập là cổ điển :). – Anshul

5

This writeup from Mozilla may answer why use closures and when

Ngoài ra, see this set of examples (especially "What can be done with Closures?" section that has the following exmples):

  • Ví dụ 1: setTimeout với Chức năng Tham khảo
  • Ví dụ 2: Kết hợp chức năng với Object Instance Phương pháp
  • Ví dụ 3: Relapsulating Rel ated Chức năng

Tôi có e cảm giác rằng điều này có thể được truy nguồn từ Crockford, nhưng việc sử dụng điển hình của việc đóng cửa là để bắt chước dụ tư nhân hoặc các biến tĩnh (mà JavaScipt thiếu)

12

Hãy nói rằng bạn muốn có một chức năng mà bạn có thể sử dụng để trả về một "id" giá trị duy nhất để sử dụng khi bạn tạo các yếu tố DOM mới . Bây giờ, trong một cái gì đó như Java, bạn có thể tạo một lớp với một bộ đếm riêng bên trong, và sau đó có một phương thức nối thêm bộ đếm vào một chuỗi tiền tố. Vâng, trong Javascript:

var getId = (function() { 
    var counter = 0; 
    return function() { 
    return "prefix" + counter++; 
    }; 
})(); 

Bây giờ biến "getId" được ràng buộc với một chức năng đó là tạo bởi chức năng khác, và tạo ra theo cách như vậy mà nó có một biến dai dẳng để sử dụng giữa lời gọi. Tương tự như vậy, nếu tôi muốn có một gia đình của các chức năng "getId" (nói, một cho từng loại phần tử DOM tôi có thể thêm vào), tôi có thể làm điều này:

var getIdFunc = function(prefix) { 
    var counter = 0; 
    return function() { 
    return prefix + counter++; 
    }; 
}; 
var getId = { 
    'div': getIdFunc('div'), 
    'span': getIdFunc('span'), 
    'dl': getIdFunc('dl'), 
    // ... 
}; 

Bây giờ tôi có thể gọi getId.div() để có được một mới "id" giá trị cho một <div> mới. Hàm được tạo bằng cách gọi một hàm cung cấp hai giá trị được lưu trữ trong một đóng: chuỗi tiền tố (được chuyển thành đối số) và bộ đếm (số var được khai báo trong phạm vi đóng).

Một khi bạn quen với nó, cơ sở rất linh hoạt và hữu ích mà bạn sẽ cảm thấy đau khi di chuyển trở lại môi trường không có nó.

Oh, và đây là một mẹo để giúp giữ cho bạn khỏi StackOverflow bạn nên cố gắng này ra: đó là một vấn đề mà bật lên tất cả các thời gian:

for (var i = 0; i < 10; ++i) { 
    var id = "foo" + i; 
    var element = document.getElementById(id); 
    element.onclick = function() { 
    alert("hello from element " + i); 
    }; 
} 

vấn đề ở đây là gì? Vâng, biến "i" được tham chiếu bởi hàm đó là "i" từ phạm vi mà vòng lặp đó chạy. Biến đó, bạn sẽ lưu ý, được tăng lên qua vòng lặp (duhh, phải không?). Vâng, mỗi một trong những chức năng nhỏ được tạo ra và được chỉ định là trình xử lý sự kiện sẽ chia sẻ cùng một biến duy nhất "i" trong phạm vi đóng. Rất tiếc! Giải pháp là làm điều gì đó như thế này:

for (var i = 0; i < 10; ++i) { 
    var id = "foo" + i; 
    var element = document.getElementById(id); 
    element.onclick = (function(iCopy) { 
    return function() { 
     alert("hello from element " + iCopy); 
    }; 
    })(i); 
} 

Chúng tôi tạo một bản sao của "i" bên ngoài thành một phạm vi khép kín của riêng nó, vì vậy hiện nay mỗi người xử lý sự kiện đều có riêng!

Để tóm tắt: kỹ thuật tận dụng đóng cửa xuất hiện tất cả thời gian freaking khi bạn quen với nó. Nó không phải là một vé miễn phí vào một xứ sở mới của lập trình không có lỗi; đừng hiểu lầm tôi. Đó là, tuy nhiên, một mô hình rất hữu ích và linh hoạt.

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