2011-01-27 31 views
17

Tôi đang cố gọi một hàm trong một đối tượng theo nghĩa đen mà tôi đã tạo, sử dụng từ khóa this. Nhưng lỗi xuất hiện cho biết this.doTheMove() không phải là chức năng:Gọi một hàm trong khai báo ký hiệu chữ cái đối tượng javascript

window.onload = function(){ 

    var animBtn = document.getElementById('startAnim'); 

    animBtn.addEventListener('click', Animation.init, false); 

} 

var Animation = { 
    init: function(){ 

    this.doTheMove(); // I'm calling the function here, but it gives an error. 

    }, 
    doTheMove: function(){ 

    alert('Animation!'); 

    } 
} 

Tại sao có lỗi?

Trả lời

16

Giải thích về những gì đang xảy ra. Câu trả lời của Pointy là tốt nhưng tôi muốn giải thích nó một cách tổng quát hơn. Một nghiên cứu rất tốt trên this có thể được tìm thấy here

Trình xử lý sự kiện chỉ là một cuộc gọi lại. Bạn vượt qua nó một chức năng và một sự kiện để lắng nghe. Tất cả những gì nó sẽ làm là gọi hàm đó.

Animation.init chỉ là bộ thu gọn cho chức năng đó. Hãy nghĩ về nó như thế này:

var callback = Animation.init 
animBtn.addEventListener('click', callback, false); 
... 
// internal browser event handler 
handler() { 
    // internal handler does stuff 
    ... 
    // Oh click event happened. Let's call that callback 
    callback(); 
} 

Vì vậy, tất cả các bạn đã thực hiện được thông qua tại

var callback = function(){ 
    this.doTheMove(); // I'm calling the function here, but it gives an error. 
} 

Theo mặc định trong javascript this === window. Điều này sẽ đề cập đến đối tượng toàn cầu nếu nó không được thiết lập cho một cái gì đó. Hiệu ứng ròng là window.doTheMove được gọi. Và chức năng đó không tồn tại.

Trong trường hợp này kể từ callback là actaully được gọi bởi trình xử lý sự kiện, các đối tượng DOM đã kích hoạt sự kiện để gọi số node.doTheMove của bạn vẫn không tồn tại.

Điều bạn muốn làm là bọc nó với tham chiếu đến Hoạt ảnh.

var callback = function() { 
    Animation.init(); 
} 

Đây là một thực hiện chức năng và nó thực thi init trên Animation. Khi bạn thực hiện nó trên một đối tượng như vậy thì nội bộ this === Animation như bạn mong đợi.

Để tổng hợp. Vấn đề ở đây là Animation.init chỉ là một tham chiếu đến một hàm. Nó không có thông tin về bất cứ điều gì khác như Pointy đã đề cập.

+3

Câu trả lời của bạn phần lớn là chính xác (hoàn toàn chính xác trong kết quả cuối cùng). Chỉ có sai lầm là * "Hiệu ứng ròng là window.doTheMove được gọi." *. Bởi vì 'init' được chuyển tới' addEventListener', nó thực sự được gọi từ ngữ cảnh của phần tử 'animBtn' để' this.doTheMove() 'có hiệu quả' animBtn.doTheMove() '. Một lần nữa, kết quả cuối cùng là như nhau. Chỉ là một chi tiết nhỏ. – user113716

+0

@patrickdw Cảm ơn tôi đã không chắc chắn liệu 'this' có được chuyển thành đối tượng DOM hay đối tượng Window hay không. Tôi không bận tâm kiểm tra nó để xác nhận. Tôi mong đợi nhiều. – Raynos

+1

+1 Và công bằng, đánh giá của bạn về 'điều này' sẽ đúng nếu nó là 'attachEvent' của Microsoft được sử dụng vì nó không (vì một lý do nào đó) đặt bối cảnh của trình xử lý. – user113716

10

Bạn cần phải thay đổi cách bạn thiết lập khả năng:

window.onload = function(){ 

    var animBtn = document.getElementById('startAnim'); 

    animBtn.addEventListener('click', function() { Animation.init(); }, false); 

} 

Trong JavaScript, thực tế là một chức năng xảy ra được xác định như là một phần của một đối tượng theo nghĩa đen thực sự không có nghĩa là rất nhiều (nếu bất cứ điều gì , trong thực tế). Tham chiếu đến Animation.initkhông đưa bạn đến đúng chức năng, nhưng vấn đề là khi hàm được gọi sau đó (để đáp ứng với "nhấp chuột" thực tế), trình duyệt gọi hàm nhưng không có ý tưởng rằng đối tượng "Hoạt ảnh "phải là tham chiếu this. Một lần nữa, thực tế là hàm được khai báo là một phần của đối tượng không có tầm quan trọng nào cả ở đây. Vì vậy, nếu bạn muốn this là một cái gì đó đặc biệt là lựa chọn của riêng bạn, sau đó bạn phải chắc chắn rằng nó được đặt rõ ràng trong mã bạn kiểm soát. Giải pháp trên là cách đơn giản nhất để thực hiện: nó xử lý các sự kiện "click" với một hàm ẩn danh không có gì khác ngoài việc gọi hàm "init" thông qua một tham chiếu rõ ràng thông qua "Animation". Điều đó sẽ đảm bảo rằng this đề cập đến đối tượng "Hoạt ảnh" khi "init" chạy.

Một lựa chọn khác sẽ được sử dụng ".bind()" cơ sở rằng một số các trình duyệt và các khuôn khổ hỗ trợ:

window.onload = function(){ 

    var animBtn = document.getElementById('startAnim'); 

    animBtn.addEventListener('click', Animation.init.bind(Animation); }, false); 

} 

Hiệu quả ròng là gần như giống hệt nhau: cuộc gọi đến ".bind()" trả về một hàm gọi hàm mà trên đó nó được gọi (đó là hàm "init" trong đối tượng "Hoạt hình"), và làm như vậy với đối số đầu tiên của nó là tham chiếu this (đối tượng "ngữ cảnh"). Đó là điều tương tự mà chúng tôi nhận được từ ví dụ đầu tiên, hoặc có hiệu quả như nhau anyway.

+0

giải thích chi tiết hơn cách truyền con trỏ hàm Animation.init và gọi nó với đối tượng 'this' không phải là' Animation'. Các giải pháp là tốt, nhưng giải thích tại sao nó không thành công ở nơi đầu tiên là thiếu. – Raynos

+0

@Raynos có bạn nói đúng, tôi sẽ thêm một số văn bản để mô tả điều đó. – Pointy

+0

Cảm ơn bạn đã trả lời, tôi sẽ kiểm tra nó ngay bây giờ – Shaoz

0

Bạn có thể muốn sử dụng phương pháp tiếp cận cơ sở portotype:

// generate a prototype object which can be instantiated 
var Animation = function() { this.doTheMove(); } 
Animation.prototype.doTheMove = function() { 
    // if the object has only one method, the whole code could be moved to 
    // var Animation = function() {...} above 
    alert('Animation!'); 
} 

Animation.prototype.otherMethod = function(param1, param2) { 
    // ... 
} 


// run the code onload 
window.onload = function(){ 
    var animBtn = document.getElementById('startAnim'); 
    animBtn.addEventListener('click', new Animation(), false); 
} 
+3

Điều này là không chính xác. 'AddEventListener' cần nhận hàm. Bạn đang truyền một đối tượng tham chiếu đến một hàm. – user113716

+0

Phải! câu trả lời của tôi là sai, sry. – Spliffster

1

Đây là một cách tiếp cận tốt đẹp khác, tôi nghĩ vậy.

window.onload = function(){ 

    var animBtn = document.getElementById('startAnim'); 

    animBtn.addEventListener('click', Animation.init, false); 

}; 

var Animation = { 
    init: function(){ 

     Animation.doTheMove(); // This will work, but your IDE may complain... 

    }, 
    doTheMove: function(){ 

     alert('Animation!'); 

    } 
}; 
0

Sáu năm rưỡi sau, nhưng tôi hy vọng câu trả lời của tôi cũng có thể cung cấp một số thông tin chi tiết cho các nhà phát triển hiện tại và tương lai.

Tôi có xu hướng mã bằng cách sử dụng các đối tượng chữ bên trong các hàm tự định nghĩa và câu hỏi gốc được đăng hoạt động tốt nếu một hàm tự thực hiện khác được thêm cùng với câu lệnh try and catch.

Điều rất quan trọng là chỉ ra rằng đó là tất cả về phạm vi và ngữ cảnh.

Vui lòng sửa bất kỳ hạn chế nào hoặc cung cấp các đề xuất hiệu quả hơn về việc sử dụng phương pháp này.

(function() { 

console.log(this); // window object 

    var animation = { 
     init: function() { 
      this.doTheMove(); 
     }, 
     doTheMove: function() { 
      alert("Animation"); 
      console.log(animation); // animation object 
     } 
    }; 

    (function() { 
     try { 
      console.log("animation.init"); // animation.init function 
      animation.init(); 
     } catch(e) { 
      console.log("Error is: " + e); 
     } 
    })(); 

})(); 
Các vấn đề liên quan