Por que certas chamadas de função são chamadas de “invocações ilegais” em JavaScript?


93

Por exemplo, se eu fizer isso:

var q = document.querySelectorAll;

q('body');

Recebo um erro de "Invocação ilegal" no Chrome. Não consigo pensar em nenhum motivo para isso ser necessário. Por um lado, não é o caso com todas as funções de código nativo. Na verdade, posso fazer isso:

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

var x = new o();

E tudo funciona bem. Em particular, descobri esse problema ao lidar com documentos e console. Alguma ideia?




Respostas:


154

É porque você perdeu o "contexto" da função.

Quando Você ligar:

document.querySelectorAll()

o contexto da função é documente estará acessível conformethis a implementação desse método.

Quando você apenas chama, qnão há mais contexto - é o windowobjeto "global" .

A implementação de querySelectorAlltenta usar, thismas não é mais um elemento DOM, é um Windowobjeto. A implementação tenta chamar algum método de um elemento DOM que não existe em um Windowobjeto e o interpretador chama foul sem surpresa.

Para resolver isso, use .bindem versões mais recentes de Javascript:

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

o que garantirá que todas as invocações subsequentes de qtenham o contexto correto. Se você não tem .bind, use isto:

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

3
Oh, boa escolha. Você está certo porque eu posso fazer: q.apply (document, ['body']); e funciona.
user1152187

Observe que isso não necessariamente funciona para funções integradas no IE. Por exemplo, console.log não tem um método apply ali.
hugomg

@Alnitak: Sim, funciona em qualquer lugar, exceto no IE e é por isso que você deve passar os argumentos normalmente, como em function q(x){ return document.querySelectorAll(x); }. Outra coisa que eu realmente gosto sobre os objetos do navegador IE é que alguns deles lançam uma exceção apenas se você tentar ler uma propriedade deles, então você precisa testar os recursos em if( 'funcname' in browserobject)vez do usual if(browserobject.funcname)!
hugomg

Excelente resposta, fiquei realmente confuso com este fenômeno, exatamente a mesma situação do OP.
Temporary_user_name

1
Mente estourada. Obrigado.
rb-

1

No meu caso, a invocação ilegal ocorreu devido à passagem de uma variável não declarada para funcionar como argumento. Certifique-se de declarar a variável antes de passar para a função.


declarar a variável não fará sentido para este caso específico, pois a invocação ilegal está acontecendo, pois o método dependente de dom está sendo chamado fora do contexto do DOM, porque no momento em que você faz q = document. algo, o somethingmétodo perde o contexto do documento
Anshul Sahni


0

Mais uma solução concisa:

const q=s=>document.querySelectorAll(s);
q('body');
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.