Pourquoi certains appels de fonction sont-ils appelés «invocations illégales» en JavaScript?


93

Par exemple, si je fais ceci:

var q = document.querySelectorAll;

q('body');

J'obtiens une erreur "Invocation illégale" dans Chrome. Je ne vois aucune raison pour laquelle cela est nécessaire. D'une part, ce n'est pas le cas avec toutes les fonctions de code natif. En fait, je peux faire ceci:

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

var x = new o();

Et tout fonctionne très bien. En particulier, j'ai découvert ce problème en traitant le document et la console. Des pensées?




Réponses:


154

C'est parce que vous avez perdu le «contexte» de la fonction.

Quand vous appelez:

document.querySelectorAll()

le contexte de la fonction est document, et sera accessible comme thispar la mise en œuvre de cette méthode.

Lorsque vous appelez simplement, qil n'y a plus de contexte - c'est l' windowobjet "global" à la place.

L'implémentation de querySelectorAllessaie d'utiliser thismais ce n'est plus un élément DOM, c'est un Windowobjet. L'implémentation essaie d'appeler une méthode d'un élément DOM qui n'existe pas sur un Windowobjet et l'interpréteur appelle sans surprise faute.

Pour résoudre ce problème, utilisez .binddans les versions plus récentes de Javascript:

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

qui garantira que toutes les invocations ultérieures de qont le bon contexte. Si vous ne l'avez pas .bind, utilisez ceci:

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

3
Oh, bon appel. Vous avez raison parce que je peux faire: q.apply (document, ['body']); et il fonctionne.
user1152187

Notez que cela ne fonctionne pas nécessairement pour les fonctions intégrées dans IE. Par exemple, console.log ne contient pas de méthode apply.
hugomg

@Alnitak: Oui, cela fonctionne partout sauf pour IE et c'est pourquoi vous devriez souvent simplement passer des arguments normalement, comme dans function q(x){ return document.querySelectorAll(x); }. Une autre chose que j'aime vraiment à propos des objets de navigateur IE est que certains d'entre eux lancent une exception juste si vous essayez de lire une propriété d'eux, vous devez donc tester les fonctionnalités avec if( 'funcname' in browserobject)au lieu de l'habituel if(browserobject.funcname)!
hugomg

Excellente réponse, j'étais vraiment confus par ce phénomène, exactement la même situation que OP.
temporary_user_name

1
L'esprit soufflé. Je vous remercie.
rb-

1

Dans mon cas, une invocation illégale s'est produite en raison du passage d'une variable non déclarée à une fonction en tant qu'argument. Assurez-vous de déclarer la variable avant de passer à la fonction.


déclarer une variable n'a pas de sens dans ce cas particulier car une invocation illégale se produit lorsque la méthode dépendante de dom est appelée hors du contexte du DOM, car au moment où vous faites q = somethingdocument
quelque chose

1

vous pouvez utiliser comme ceci:

let qsa = document.querySelectorAll;
qsa.apply(document,['body']);

0

Encore une solution concise:

const q=s=>document.querySelectorAll(s);
q('body');
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.