2012-10-21 35 views
13

Possible Duplicate:
If Javascript has first-class functions, why doesn’t this work?Bí danh hàm trong javascript

Khi tôi cố gắng để thực hiện một chức năng bí danh cho document.getElementById như sau:

f = document.getElementById; 

Tuy nhiên, khi tôi cố gắng gọi:

var e_fullname = f(“fullname”); 

Nó được vươn một lỗi: Could not convert JavaScript argument

Và bên dưới là OK:

var e_fullname = f.call(document, “funname”); 

Bạn có thể cho tôi biết lý do không?

+2

Bạn có một số dấu ngoặc kép bất thường. Bạn đang sử dụng trình chỉnh sửa nào? – 0x499602D2

+8

@David lập trình viên thực sự sử dụng Word –

+0

Tôi không nghĩ rằng vấn đề này bởi vì một trình soạn thảo. Tôi chỉ hiểu Javascript hoạt động như thế nào? – vietean

Trả lời

20

Có bốn cách gọi một hàm:

  1. Chức năng gọi: f(p1, p2)
  2. Cách gọi: obj.f(p1, p2)
  3. Apply hoặc gọi gọi: f.apply(obj, [p1, p2]), f.call(obj, p1, p2)
  4. Constructor gọi: new f(p1, p2)

Trong tất cả các trường hợp này, f chỉ là một tham chiếu (con trỏ) đến một đối tượng hàm (một đối tượng có thuộc tính nội bộ [[Call]]). Điều gì làm cho nó hoạt động khác nhau trong tất cả các trường hợp này là cách hàm được gọi, và điều đó rất quan trọng.

Vì vậy, f chỉ là một tham chiếu đến đối tượng getElementById, không có sự khác biệt giữa document.getElementByIdsomeOtherHTMLElement.getElementById; hàm không giữ lại tham chiếu đến đối tượng tham chiếu đến nó.

Nếu bạn muốn để ràng buộc một số "chủ sở hữu" đối tượng, sử dụng các phương pháp bind:

var f = document.getElementById.bind(document); 
1

Bạn có thể sử dụng bind

Creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function was called.

var f = document.getElementById.bind(document); 

Nó được giới thiệu vào ES5, vì vậy hãy ý thức về các trình duyệt chưa hỗ trợ phiên bản này của ECMAScript!

Là một thay thế bạn có thể sử dụng phương pháp proxy của jQuery, được thêm vào trong phiên bản 1.4

var f = ​$.proxy(document.getElementById, document); 

Hoặc bạn có thể delcare f như một chức năng của riêng nó (đây là một giải pháp tiết hơn).

var f = function() { return document.getElementById(arguments); } 
+0

Tôi chỉ muốn chỉ ra rằng JavaScript phiên bản bạn đang đề cập đến là dành riêng cho Mozilla. Nếu bạn đang xem xét các trình duyệt khác, sẽ hữu ích hơn khi tham khảo phiên bản ECMAScript. '.bind' được giới thiệu trong ES5. –

+0

Cảm ơn @FelixKling Tôi đã thay đổi nó trong văn bản. – clentfort

+1

Người cuối cùng không hoạt động, đối số không thể được truyền lại trực tiếp như vậy. Bạn cần phải làm một cái gì đó như 'document.getElementById.apply (tài liệu, Array.prototype.slice.call (đối số));' –

5

getElementById là một phương pháp trên tài liệu. Để gọi nó, người thông dịch cần phải có chính cơ thể chức năng, đối tượng để gọi nó trên (tài liệu trong trường hợp của bạn), và các đối số.

Khi bạn làm f = document.getElementById, bạn đang sao chép nội dung chức năng chứ không phải đối tượng để gọi.

Khi bạn làm điều này:

f.call(document, “funname”); 

Bạn đang cung cấp tất cả các đối tượng để gọi nó về, và các đối số.

Nếu bạn muốn có thể gọi trực tiếp f, bạn cần lấy đối tượng "tài liệu" được lưu trữ trong đó bằng cách nào đó. Dễ nhất là:

var f = function(name){return document.getElementById(name)} 

Điều này tạo ra một đóng cửa giữ giá trị tài liệu cho bạn.

Bạn cũng có thể sử dụng bind() để thực hiện tương tự.