Tại sao phải định nghĩa một hàm ẩn danh và chuyển nó vào jQuery làm đối số?


96

Tôi đang xem qua mã demo peepcode tuyệt vời từ các screencasts của backbone.js. Trong đó, toàn bộ mã xương sống được bao bọc trong một hàm ẩn danh được truyền vào đối tượng jQuery:

(function($) {
  // Backbone code in here
})(jQuery);

Trong mã xương sống của riêng tôi, tôi vừa gói tất cả mã của mình trong sự kiện jQuery DOM 'ready':

$(function(){
  // Backbone code in here
});

Điểm / lợi thế của cách tiếp cận đầu tiên là gì? Làm theo cách này sẽ tạo ra một hàm ẩn danh sau đó được thực thi ngay lập tức với đối tượng jQuery được truyền làm đối số hàm, đảm bảo hiệu quả rằng $ là đối tượng jQuery. Đây có phải là điểm duy nhất - để đảm bảo rằng jQuery bị ràng buộc với '$' hay có những lý do nào khác để làm điều này?


4
Thay vào đó, bạn nên duyệt SO trước.
Alexander

Khả năng tương tác với các thư viện khác - nếu tác giả trang cần sử dụng $.noConflict(), ví dụ đầu tiên vẫn hoạt động.
DCoder

Có thể trùng lặp: jQuery và $ câu hỏi
Alexander

Xem thể trùng lặp document.ready jQuery vs tự gọi hàm nặc danh cho sự khác biệt
Bergi

@Alexander nhưng sau đó những người khác sẽ tìm thấy câu hỏi này trên SO trước. :-)
caiosm1005

Câu trả lời:


179

Hai khối mã bạn đã hiển thị khác nhau đáng kể về thời gian và lý do chúng thực thi. Chúng không loại trừ nhau. Chúng không phục vụ cùng một mục đích.

Mô-đun JavaScript


(function($) {
  // Backbone code in here
})(jQuery);

Đây là một mẫu "Mô-đun JavaScript", được triển khai với một hàm gọi ngay lập tức.

Mục đích của mã này là cung cấp "tính mô-đun", quyền riêng tư và tính đóng gói cho mã của bạn.

Việc thực hiện điều này là một hàm ngay lập tức được gọi bởi (jQuery)dấu ngoặc đơn. Mục đích của việc chuyển jQuery vào trong dấu ngoặc đơn là cung cấp phạm vi cục bộ cho biến toàn cục. Điều này giúp giảm thiểu chi phí tìm kiếm $biến và cho phép nén / tối ưu hóa tốt hơn cho các bộ thu nhỏ trong một số trường hợp.

Các hàm gọi ngay lập tức được thực thi, tốt, ngay lập tức. Ngay sau khi định nghĩa hàm hoàn tất, hàm được thực thi.

Hàm "DOMReady" của jQuery

Đây là bí danh của hàm "DOMReady" của jQuery: http://api.jquery.com/ready/


$(function(){
  // Backbone code in here
});

Hàm "DOMReady" của jQuery thực thi khi DOM sẵn sàng được điều khiển bởi mã JavaScript của bạn.

Mô-đun so với DOMReady trong mã xương sống

Việc xác định mã Backbone của bạn bên trong hàm DOMReady của jQuery là không tốt và có khả năng gây hại cho hiệu suất ứng dụng của bạn. Hàm này không được gọi cho đến khi DOM được tải và sẵn sàng được thao tác. Điều đó có nghĩa là bạn đang đợi cho đến khi trình duyệt phân tích cú pháp DOM ít nhất một lần trước khi bạn xác định các đối tượng của mình.

Ý tưởng tốt hơn là xác định các đối tượng Backbone của bạn bên ngoài một hàm DOMReady. Tôi, trong số nhiều người khác, thích làm điều này bên trong một mẫu Mô-đun JavaScript để tôi có thể cung cấp tính năng đóng gói và bảo mật cho mã của mình. Tôi có xu hướng sử dụng mẫu "Mô-đun tiết lộ" (xem liên kết đầu tiên ở trên) để cung cấp quyền truy cập vào các bit mà tôi cần bên ngoài mô-đun của mình.

Bằng cách xác định các đối tượng của bạn bên ngoài hàm DOMReady và cung cấp một số cách để tham chiếu đến chúng, bạn đang cho phép trình duyệt bắt đầu xử lý JavaScript của bạn, có khả năng tăng tốc trải nghiệm người dùng. Nó cũng làm cho mã linh hoạt hơn vì bạn có thể di chuyển mọi thứ mà không phải lo lắng về việc tạo thêm các hàm DOMREady khi bạn di chuyển mọi thứ.

Bạn vẫn có thể sử dụng hàm DOMReady, ngay cả khi bạn xác định các đối tượng Backbone ở một nơi khác. Lý do là nhiều ứng dụng Backbone cần thao tác DOM theo một số cách. Để làm điều này, bạn cần đợi cho đến khi DOM sẵn sàng, do đó bạn cần sử dụng hàm DOMReady để khởi động ứng dụng của mình sau khi nó đã được xác định.

Bạn có thể tìm thấy rất nhiều ví dụ về điều này trên web, nhưng đây là cách triển khai rất cơ bản, sử dụng cả Mô-đun và chức năng DOMReady:



// Define "MyApp" as a revealing module

MyApp = (function(Backbone, $){

  var View = Backbone.View.extend({
    // do stuff here  
  });

  return {
    init: function(){
      var view = new View();
      $("#some-div").html(view.render().el);
    }
  };

})(Backbone, jQuery);



// Run "MyApp" in DOMReady

$(function(){
  MyApp.init();
});

1
Cảm ơn vì phản hồi chi tiết này. Tôi biết về hàm DOMReady chỉ gọi khi sự kiện DOM sẵn sàng kích hoạt, nhưng chưa bao giờ thực sự nghĩ rằng đó sẽ là một vấn đề. Tách mã vào việc xác định các bit xương sống bên trong một mô-đun, và sau đó tương tác với họ trong tư thế sẵn sàng dom không thực sự có vẻ như phương pháp tốt nhất
Matt Roberts

2
Thật thú vị, ứng dụng ví dụ "việc làm" với src xương sống đặt mọi thứ ở trạng thái sẵn sàng.
Matt Roberts,

2
Đừng quên mô-đun javascript còn được gọi là an IIFE.
Jess

1
Hàm ẩn danh về cơ bản được thực thi cùng lúc với DOM sẵn sàng, vậy làm cách nào để làm cho chúng hiệu quả hơn ??
bhavya_w

14

Là một phụ chú nhỏ, việc gửi $ dưới dạng một đối số cho một hàm ẩn danh làm cho $ cục bộ cho hàm đó, điều này có một hàm ý nhỏ về hiệu suất tích cực nếu hàm $ được gọi nhiều. Điều này là do javascript tìm kiếm phạm vi cục bộ cho các biến trước và sau đó chuyển xuống phạm vi cửa sổ (nơi $ thường tồn tại).


9

Nó đảm bảo bạn luôn có thể sử dụng $bên trong nắp đó ngay cả khi $.noConflict()đã được sử dụng.

Nếu không có sự đóng cửa này, bạn sẽ phải sử dụng jQuerythay vì $toàn bộ thời gian.



2

Sử dụng cả hai.

Hàm tự gọi mà bạn truyền vào jQuery để ngăn xung đột thư viện và chỉ để đảm bảo rằng jQuery có sẵn như bạn mong đợi với $.

Và phương thức phím tắt .ready () theo yêu cầu để chạy javascript chỉ sau khi DOM đã tải:

(function($) {
    $(function(){
          //add code here that needs to wait for page to be loaded
    });

    //and rest of code here
})(jQuery);

Một phiên bản ngắn hơn tôi tìm thấy ở đâu đó trên SO (cũng bảo vệ không xác định) :jQuery(function ($, undefined) { /* Code */ });
Jared Gotte
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.