2009-08-26 23 views
32

Xem:Tiếp cận bên ngoài biến trong vòng từ javascript đóng cửa

for (var i in this.items) { 
    var item = this.items[i]; 
    $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>"); 
    $("#showcasebutton_"+item.id).click(function() { 
     alert(item.id); 
     self.switchto(item.id); 
    }); 
} 

Vấn đề là các item.id cảnh báo luôn là id của mục cuối cùng trong mảng (this.items). Giải quyết thế nào?

Trả lời

40

Vấn đề bạn có ở đây là rằng item thay đổi biến với mỗi vòng lặp. Khi bạn đang tham chiếu item tại một số điểm sau này, giá trị cuối cùng mà nó được giữ sẽ được sử dụng. Bạn có thể sử dụng một kỹ thuật được gọi là closure (về bản chất là một hàm trả về một hàm) để nhanh chóng phạm vi biến khác nhau.

for (var i in this.items) { 
      var item = this.items[i]; 
      $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>"); 
      $("#showcasebutton_"+item.id).click( 
       // create an anonymous function that will scope "item" 
       (function(item) { 
        // that returns our function 
        return function() { 
        alert(item.id); 
        self.switchto(item.id); 
        }; 
       })(item) // immediately call it with "item" 
      ); 
    } 

Lưu ý phụ - Tôi thấy bạn có jQuery ở đây. Nó có một hàm trợ giúp $.each() có thể được sử dụng với các mảng và có thể là một phím tắt cho đơn giản cho/mỗi vòng lặp. Do cách phạm vi hoạt động trong cuộc gọi này - bạn sẽ không cần sử dụng lệnh đóng vì "mục" đã là tham số của hàm khi được gọi, không được lưu trữ trong phạm vi var trong phạm vi chức năng của cha mẹ, như đã đúng trong thí dụ.

$.each(this.items,function(i, item) { 
    $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>"); 
    $("#showcasebutton_"+item.id).click(function() { 
    alert(item.id); 
    self.switchto(item.id); 
    }); 
}); 
+1

Tìm thấy một giải pháp thanh lịch hơn cho bạn sau khi thực tế - hãy kiểm tra lợi thế của việc sử dụng '$ .each()' – gnarf

+0

Cảm ơn bạn! Tôi chỉ dành một thời gian cố gắng tạo ra một đóng cửa để sử dụng một biến địa phương bên trong gọi lại nhấp chuột của tôi. Phần khó khăn cho tôi loại bỏ các tham số từ hàm được trả về. – Sam

0

thử vòng lặp này

for (var i=0; i < this.items.length; i++) { 
    this.items[i] 
}; 
+0

Không, vòng lặp là tốt. Vấn đề là mọi mục danh sách được thêm sẽ thấy cùng một "item.id" trong phần đóng. –

4

Cách khác để tiếp cận điều này là đảm bảo hoạt động kinh doanh = items[i] được thực hiện hiệu quả bằng cách gọi hàm. Trong tốc ký, điều này:

for (var i in this.items) { 
    (function(item) { 
     $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>"); 
     $("#showcasebutton_"+item.id).click(function() { 
      alert(item.id); 
      self.switchto(item.id); 
     }); 
    })(this.items[i]); 
} 

Các chức năng ẩn danh có một chút lộn xộn, làm cho nó khá thích hợp hơn để có một không-để-nặc danh xung quanh cho mục đích này, nhưng nó lừa.

1

Javascript đóng cửa lưu trữ tham chiếu đến các biến của chúng, vì vậy tất cả các trình xử lý onclick của bạn đang sử dụng cùng một biến.

Bạn cần phải nắm bắt các biến trong một chức năng trung gian, như thế này:

function buildClickHandler(pageNumber) { 
    return function() { //Create and return a new function 
     alert(item.id); 
     self.switchto(item.id); 
    } 
} 

Sau đó, sử dụng có chức năng tạo click xử lý, như thế này:

for (var i in this.items) { 
    var item = this.items[i]; 
    $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>"); 

    $("#showcasebutton_"+item.id).click(buildClickHandler(item)); 
} 

Mỗi cuộc gọi đến buildClickHandler tạo một đóng cửa riêng biệt có biến riêng của nó.

0

Tôi biết rất rõ rằng đây là một bài đăng cũ, nhưng dường như những người thiết kế jQuery (mà tôi cho rằng bạn phải sử dụng) đã đưa ra giải pháp tối ưu nhất cho vấn đề của bạn.

Trong phiên bản 1.4 mới của thư viện, they have added the jQuery.proxy() function. Điều này cho phép bạn sửa đổi hiệu quả ngữ cảnh/phạm vi chức năng mà bạn đang gọi - thực hiện theo cách jQuery, đảm bảo rằng bạn có thể ngừng sử dụng các kỹ thuật có khả năng gây rối mọi thứ.

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