Почему в JavaScript определенные вызовы функций называются «незаконными вызовами»?


97

Например, если я сделаю это:

var q = document.querySelectorAll;

q('body');

Я получаю сообщение об ошибке «Незаконный вызов» в Chrome. Я не могу придумать ни одной причины, по которой это необходимо. Во-первых, это не относится ко всем функциям машинного кода. На самом деле я могу это сделать:

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

var x = new o();

И все работает нормально. В частности, я обнаружил эту проблему при работе с документом и консолью. есть идеи?




Ответы:


158

Это потому, что вы потеряли «контекст» функции.

Когда вы звоните:

document.querySelectorAll()

контекст функции есть documentи будет доступен thisпри реализации этого метода.

Когда вы просто вызываете q, больше нет контекста - windowвместо этого появляется «глобальный» объект.

Реализация querySelectorAllпытается использовать, thisно это уже не элемент DOM, это Windowобъект. Реализация пытается вызвать какой-то метод элемента DOM, которого нет в Windowобъекте, и интерпретатор неудивительно вызывает ошибку.

Чтобы решить эту проблему, используйте .bindв новых версиях Javascript:

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

что гарантирует, что все последующие вызовы будут qиметь правильный контекст. Если у вас нет .bind, используйте это:

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

3
О, хороший звонок. Вы правы, потому что я умею: q.apply (document, ['body']); и это работает.
user1152187

Обратите внимание, что это не обязательно для встроенных функций в IE. Например, в console.log нет метода apply.
hugomg

@Alnitak: Да, он работает везде, кроме IE, и поэтому часто нужно просто передавать аргументы нормально, как в function q(x){ return document.querySelectorAll(x); }. Еще одна вещь, которая мне очень нравится в объектах браузера IE, - это то, что некоторые из них выдают исключение, если вы пытаетесь прочитать из них свойство, поэтому вам нужно тестировать функции с помощью if( 'funcname' in browserobject)вместо обычных if(browserobject.funcname)!
hugomg

Отличный ответ, меня очень смутило это явление, точно такая же ситуация, что и OP.
temporary_user_name

1
Разум взорван. Спасибо.
rb

1

В моем случае незаконный вызов произошел из-за передачи необъявленной переменной в качестве аргумента. Обязательно объявите переменную перед переходом к функции.


объявление переменной не имеет смысла в этом конкретном случае, поскольку происходит незаконный вызов, поскольку зависимый от dom метод вызывается из контекста DOM, потому что в тот момент, когда вы выполняете q = document.something, somethingметод теряет контекст документа
Аншул Сахни


0

Еще одно лаконичное решение:

const q=s=>document.querySelectorAll(s);
q('body');
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.