Tại sao các lệnh gọi hàm nhất định được gọi là “lệnh gọi bất hợp pháp” trong JavaScript?


96

Ví dụ: nếu tôi làm điều này:

var q = document.querySelectorAll;

q('body');

Tôi gặp lỗi "Lệnh gọi bất hợp pháp" trong Chrome. Tôi không thể nghĩ ra bất kỳ lý do tại sao điều này là cần thiết. Đối với một, nó không phải là trường hợp với tất cả các hàm mã gốc. Trên thực tế, tôi có thể làm điều này:

var o = Object; // which is a native code function

var x = new o();

Và mọi thứ hoạt động tốt. Đặc biệt, tôi đã phát hiện ra vấn đề này khi xử lý tài liệu và bảng điều khiển. Có suy nghĩ gì không?




Bản sao chính xác của "Uncaught TypeError:
Non lậu

Câu trả lời:


157

Đó là bởi vì bạn đã mất "ngữ cảnh" của hàm.

Khi bạn gọi:

document.querySelectorAll()

ngữ cảnh của chức năng đang documentvà sẽ có thể truy cập được khi thisthực hiện phương pháp đó.

Khi bạn vừa gọi q, không còn ngữ cảnh nữa - windowthay vào đó là đối tượng "toàn cục" .

Việc triển khai querySelectorAllcố gắng sử dụng thisnhưng nó không còn là một phần tử DOM nữa, nó là một Windowđối tượng. Việc triển khai cố gắng gọi một số phương thức của phần tử DOM không tồn tại trên một Windowđối tượng và trình thông dịch không ngạc nhiên gọi là lỗi.

Để giải quyết vấn đề này, hãy sử dụng .bindtrong các phiên bản Javascript mới hơn:

var q = document.querySelectorAll.bind(document);

điều này sẽ đảm bảo rằng tất cả các lệnh gọi tiếp theo của qđều có ngữ cảnh phù hợp. Nếu bạn chưa có .bind, hãy sử dụng cái này:

function q() {
    return document.querySelectorAll.apply(document, arguments);
}

3
Ồ, cuộc gọi tốt. Bạn đúng vì tôi có thể làm: q.apply (document, ['body']); Và nó hoạt động.
user1152187

Lưu ý rằng điều này không cần thiết hoạt động đối với các chức năng nội trang trong IE. Ví dụ, console.log không có phương thức áp dụng ở đó.
ômomg

@Alnitak: Đúng vậy, nó hoạt động ở mọi nơi ngoại trừ IE và đó là lý do tại sao bạn thường chỉ nên chuyển đối số bình thường, như trong function q(x){ return document.querySelectorAll(x); }. Một điều khác mà tôi thực sự thích về các đối tượng trình duyệt IE là một số trong số chúng ném ra một ngoại lệ chỉ khi bạn cố gắng đọc một thuộc tính từ chúng, vì vậy bạn cần phải kiểm tra các tính năng if( 'funcname' in browserobject)thay vì thông thường if(browserobject.funcname)!
ômomg

Câu trả lời xuất sắc, tôi thực sự bối rối trước hiện tượng này, tình huống giống hệt như OP.
temporary_user_name

1
Tâm trí bị thổi bay. Cảm ơn bạn.
rb-

1

Trong trường hợp của tôi, đã xảy ra lệnh gọi bất hợp pháp do chuyển biến không khai báo cho hàm làm đối số. Đảm bảo khai báo biến trước khi chuyển đến hàm.


khai báo biến sẽ không có ý nghĩa đối với trường hợp cụ thể này vì lệnh gọi bất hợp pháp đang xảy ra vì phương thức phụ thuộc dom đang được gọi ra khỏi ngữ cảnh của DOM, bởi vì thời điểm bạn thực hiện q = document. một cái gì đó somethingphương thức này làm mất ngữ cảnh của tài liệu
Anshul Sahni


0

Một giải pháp ngắn gọn hơn:

const q=s=>document.querySelectorAll(s);
q('body');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.