2012-01-07 18 views
20

JavaScript được mục đích để có chức năng hạng nhất, vì vậy đây có vẻ như những điều sau đây nên làm việc:Nếu JavaScript có chức năng hạng nhất, tại sao không gọi hàm này trong một công việc biến?

var f = document.getElementById; 
var x = f('x'); 

Nhưng nó không thành công trên tất cả các trình duyệt, với một thông điệp báo lỗi khó hiểu khác nhau trên mỗi một. Safari nói "Lỗi loại". Chrome nói “Gọi bất hợp pháp”. Firefox nói “Không thể chuyển đổi đối số JavaScript”.

Tại sao?

Trả lời

19

Vì trong các hàm JavaScript arent bị ràng buộc thành ngữ cảnh (this). Bạn có thể sử dụng bind():

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

Để làm rõ câu trả lời này, 'this' trong' tài liệu .getElementById() 'là' document', trong khi 'this' mà bạn đang thực hiện phạm vi của bạn là phạm vi toàn cục, còn' this' là đối tượng 'window'. –

36

Khi bạn gọi obj.method() trong Javascript, phương pháp được thông qua objthis. Gọi số document.getElementById('x') do đó đặt this thành document.

Tuy nhiên, nếu bạn chỉ viết f = document.getElementById bạn hiện có tham chiếu mới cho hàm, nhưng tham chiếu đó không còn "bị ràng buộc" với document nữa.

Vì vậy, mã của bạn không hoạt động vì khi bạn gọi f làm tên chức năng trần, nó sẽ kết thúc với đối tượng toàn cầu (window). Ngay khi nội bộ của hàm cố gắng sử dụng this, nó phát hiện ra rằng nó hiện có một số window thay vì một số document và không ngạc nhiên là nó không thích nó.

Bạn thể làm f làm việc nếu bạn gọi nó như vậy:

var x = f.call(document, 'x'); 

trong đó kêu gọi f nhưng rõ ràng thiết lập ngữ cảnh để document.

Cách khác để sửa lỗi này là sử dụng Function.bind() mà chỉ có sẵn trong ES5:

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

và thực sự chỉ là một cắt ngắn tổng quát để tạo wrapper của riêng bạn mà đặt đúng bối cảnh:

function f(id) { 
    return document.getElementById(id); 
} 
3

Sử dụng toán tử lây lan ES6, bạn cũng có thể thử:

function f(){ 
    return document.getElementById(...arguments); 
}; 

Babel cho này:

function f() { 
    var _document; 
    return (_document = document).getElementById.apply(_document, arguments); 
}; 
Các vấn đề liên quan