If JavaScript has first-class functions, why doesn’t calling this function in a variable work?

JavaScript is purported to have first-class functions, so this seems like the following ought to work:

var f = document.getElementById;
var x = f('x');

But it fails on all browsers, with a different cryptic error message on each one. Safari says “Type error”. Chrome says “Illegal invocation”. Firefox says “Could not convert JavaScript argument”.

Why?

Answers:

Answer

Because in JavaScript functions arent bound to context (this). You may use bind():

var f = document.getElementById.bind(document);
Answer

Using ES6's spread operator, you could also try:

function f(){
    return document.getElementById(...arguments);
};

Babel gives this:

function f() {
    var _document;
    return (_document = document).getElementById.apply(_document, arguments);
};
Answer

When you call obj.method() in Javascript the method is passed obj as this. Calling document.getElementById('x') with therefore set this to document.

However if you just write f = document.getElementById you now have a new reference to the function, but that reference is no longer "bound" to document.

So your code doesn't work because when you call f as a bare function name it ends up bound to the global object (window). As soon as the innards of the function try to use this it finds that it now has a window instead of a document and unsurprisingly it doesn't like it.

You can make f work if you call it so:

var x = f.call(document, 'x');

which calls f but explicitly sets the context to document.

The others way to fix this is to use Function.bind() which is only available in ES5:

var f = document.getElementById.bind(document);

and is really just a generalised short cut for creating your own wrapper that correctly sets the context:

function f(id) {
    return document.getElementById(id);
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.