112

For example, if I do this:

var q = document.querySelectorAll;

q('body');

I get an "Illegal invocation" error in Chrome. I can't think of any reason why this is necessary. For one, it's not the case with all native code functions. In fact I can do this:

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

var x = new o();

And everything works just fine. In particular I've discovered this problem when dealing with document and console. Any thoughts?

Robert Harvey
  • 168,684
  • 43
  • 314
  • 475
user1152187
  • 1,157
  • 2
  • 7
  • 3
  • possible duplicate of [Why can't one set an alias to document.getElementById()?](http://stackoverflow.com/questions/10723496/why-cant-one-set-an-alias-to-document-getelementbyid) – Quentin May 24 '12 at 18:54
  • 1
    possible duplicate of [JavaScript function aliasing doesn't seem to work](http://stackoverflow.com/questions/1007340/javascript-function-aliasing-doesnt-seem-to-work) – HoLyVieR May 24 '12 at 18:56
  • Exact duplicate of ["Uncaught TypeError: Illegal invocation" in Chrome](http://stackoverflow.com/questions/9677985/uncaught-typeerror-illegal-invocation-in-chrome) – Dan Dascalescu Sep 02 '16 at 23:45
  • They're similar, but not the same (only the answer is the same). In one case the OP assigns the function to a free variable and call it (global context), in another case OP assigns the function to an object property and call it (object context). Users come from search engines might not know that. – user202729 Dec 30 '20 at 01:50

3 Answers3

178

It's because you've lost the "context" of the function.

When you call:

document.querySelectorAll()

the context of the function is document, and will be accessible as this by the implementation of that method.

When you just call q there's no longer a context - it's the "global" window object instead.

The implementation of querySelectorAll tries to use this but it's no longer a DOM element, it's a Window object. The implementation tries to call some method of a DOM element that doesn't exist on a Window object and the interpreter unsurprisingly calls foul.

To resolve this, use .bind in newer versions of Javascript:

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

which will ensure that all subsequent invocations of q have the right context. If you haven't got .bind, use this:

function q() {
    return document.querySelectorAll.apply(document, arguments);
}
Alnitak
  • 313,276
  • 69
  • 379
  • 466
  • 4
    Oh, good call. You're right because I can do: q.apply(document, ['body']); and it works. – user1152187 May 24 '12 at 18:55
  • Note that this does not necessarilty work for builtin functions in IE. For example, console.log does not have an apply method there. – hugomg May 24 '12 at 19:06
  • @Alnitak: Yep, it works everywhere except for IE and is why you should often just pass arguments normaly, as in `function q(x){ return document.querySelectorAll(x); }`. Another thing I really like about IE browser objects is that some of them throw an exception just if you try to read a property from them, so you need to test features with `if( 'funcname' in browserobject)` instead of the usual `if(browserobject.funcname)`! – hugomg May 24 '12 at 19:42
  • Excellent answer, I was really confused by this phenomenon, exact same situation as OP. – temporary_user_name Aug 22 '14 at 14:48
  • 1
    Mind blown. Thank you. – rb- Feb 13 '18 at 04:05
-1

In my case Illegal invocation occurred due to passing undeclared variable to function as argument. Make sure to declare variable before passing to function.

Fawad
  • 37
  • 2
  • 1
    declaring variable won't make sense to this particular case as illegal invocation is happening as dom dependent method is being called out of the context of DOM, because the moment you do q = document.something the `something` method looses context of document – Anshul Sahni Apr 14 '18 at 06:36
-1

you can use like this :

let qsa = document.querySelectorAll;
qsa.apply(document,['body']);
love-for-coding
  • 189
  • 1
  • 6