2009-07-09 22 views
24

Tại sao tôi không thể sử dụng setTimeout trong đối tượng javascript?Cách sử dụng "setTimeout" để gọi chính đối tượng

Message = function() { 

    ... 
    ...   

    this.messageFactory = ... 
    this.feedbackTag = document.getElementById('feedbackMessages'); 

    this.addInfo = function (message) { 
     var info = this.messageFactory.createInfo(message); // create a div 
     this.feedbackTag.appendChild(info); 

     setTimeout('this.feedbackTag.removeChild(info)', 5000); 
     // why in here, it complain this.feedbacktag is undefined ?????? 

    }; 
} 

Cám ơn Steve`s Solution, bây giờ nó sẽ làm việc nếu mã là như sau ... vì 'này' trước đã thực sự trỏ đến các chức năng trong setTimeout, nó có thể không nhắn rearch.

Message = function() { 

    ... 
    ...   

    this.messageFactory = ... 
    this.feedbackTag = document.getElementById('feedbackMessages'); 

    this.addInfo = function (message) { 
     var info = this.messageFactory.createInfo(message); // create a div 
     this.feedbackTag.appendChild(info); 

     var _this = this; 
     setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 

    }; 
} 

Nhưng tại sao doesn `t cho nó hoạt động nếu chúng ta làm điều này:

Message = function() { 

    ... 
    ...   

    this.messageFactory = ... 
    this.feedbackTag = document.getElementById('feedbackMessages'); 
    // public function 
    this.addInfo = function (message) { 
     var info = this.messageFactory.createInfo(message); // create a div 
     this.feedbackTag.appendChild(info); 

     delayRemove(info); 

    }; 
    // private function 
    function delayRemove(obj) { 
     var _this = this; 
     setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 
    } 
} 
+0

có thể trùng lặp của [Cách truy cập đúng 'this'/context bên trong một cuộc gọi lại?] (Http://stackoverflow.com/q/20279484/1048572) – Bergi

+0

Trùng lặp: [setTimeout() bên trong JavaScript Lớp bằng cách sử dụng" this ”] (Http://stackoverflow.com/questions/5911211/settimeout-inside-javascript-class-using-this) và [Sử dụng setTimeout() trong một hàm lớp JavaScript] (http://stackoverflow.com/questions/ 6997921/sử dụng-settimeout-trong-a-javascript-class-chức năng) – handle

Trả lời

84

Hãy thử thay thế dòng này:

setTimeout('this.feedbackTag.removeChild(info)', 5000); 

với hai dòng sau:

var _this = this; 
setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 

Lưu ý:

Không bao giờ vượt qua setTimeout một chuỗi, vì điều này gọi eval (bạn chỉ nên sử dụng khi cần thiết). Thay vào đó, hãy chuyển setTimeout tham chiếu hàm (đây có thể là một hàm ẩn danh).

Cuối cùng, hãy luôn kiểm tra xem từ khóa this có trỏ đến những gì bạn nghĩ nó trỏ đến không (xem http://www.alistapart.com/articles/getoutbindingsituations).

Addressing Câu hỏi 2:

Tôi tin rằng cho các chức năng bình thường, this được thiết lập để các window đối tượng không phân biệt nơi chúng được khai báo. Vì vậy, việc di chuyển mã vào một hàm riêng biệt sẽ không khắc phục được sự cố.

+1

Nó sẽ không giới thiệu một rò rỉ bộ nhớ? – tsilb

+1

@shrimpy: Đó là một vấn đề phức tạp, nhưng bài viết này mô tả nó khá tốt: http://www.alistapart.com/articles/getoutbindingsituations. Về cơ bản, "this" không trỏ đến lớp Message bên trong hàm ẩn danh. Để khắc phục vấn đề này, chúng ta tạo một biến (tôi gọi nó là "_this"), làm cho nó trỏ tới lớp Message đúng, và sau đó sử dụng biến này khi chúng ta muốn tham khảo lớp bên trong hàm ẩn danh. –

+0

@tslib: Theo cách nào? Cách giải quyết này khá phổ biến. Nếu bạn lo lắng rằng chức năng ẩn danh sẽ giữ cho mọi thứ bị trói lại, tôi khá chắc chắn rằng nó sẽ được zapped bởi Garbage Collector ngay sau khi "setTimeout" đã kết thúc với nó. –

2

Để trả lời câu hỏi cuối cùng của bạn: "Tại sao doesn` t cho nó hoạt động nếu chúng ta làm được điều này":

Message = function() { 

... 
...   

this.messageFactory = ... 
this.feedbackTag = document.getElementById('feedbackMessages'); 
// public function 
this.addInfo = function (message) { 
    var info = this.messageFactory.createInfo(message); // create a div 
    this.feedbackTag.appendChild(info); 

    delayRemove(info); 

}; 
// private function 
function delayRemove(obj) { 
    var _this = this; 
    setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 
}} 

Nó không làm việc vì bạn đang đi qua một biến không xác định (info) thay vì một biến định nghĩa (obj). Dưới đây là chức năng điều chỉnh:

function delayRemove(obj) { 
var _this = this; 
setTimeout(function() { _this.feedbackTag.removeChild(obj); }, 5000);} 
9

Một cách gọn gàng là chỉ cần vượt qua này như một tham số cho hàm được gọi trong thời gian chờ:

function delayRemove(obj) { 
    setTimeout(function(_this) { 
     _this.feedbackTag.removeChild(obj); 
    }, 5000, this); 
} 

Bạn thực sự cần vượt qua obj như một đối số nữa, chỉ để đảm bảo rằng nó nằm trong phạm vi (số tham số không giới hạn):

function delayRemove(obj) { 
    setTimeout(function(_this, removeObj) { 
     _this.feedbackTag.removeChild(removeObj); 
    }, 5000, this, obj); 
} 

HTML5 và Node.js mở rộng chức năng setTimeout để chấp nhận tham số được chuyển đến hàm gọi lại của bạn. Nó có chữ ký phương thức sau.

setTimeout(callback, delay, [param1, param2, ...])

Như setTimeoutisn't actually a JavaScript feature kết quả của bạn có thể khác nhau giữa các trình duyệt. Tôi không thể tìm thấy bất kỳ chi tiết cụ thể nào về hỗ trợ, tuy nhiên như tôi đã nói đây là thông số kỹ thuật HTML5.

+1

tất cả các trình duyệt hiện hỗ trợ tham số thứ ba của setTimeout? – StefanoCudini

+0

@StefanoCudini Đã cập nhật câu trả lời. –

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