Why can't I omit the parameter of getElementById() in the Arrow Function?

Say I have 3 <img> tags on a page, and I would like to get these as an array, so I wrote:

let myArray = ['img1', 'img2', 'img3'].map(id => document.getElementById(id));

... which worked well.

Then I thought, hey, getElementById takes exactly 1 argument. Isn't there a syntax sugar for that? So I wrote:

let myArray = ['img1', 'img2', 'img3'].map(document.getElementById);

... but that didn't work. I got "Illegal invocation" on Chrome.

So it's not syntax sugar then. What's behind all these?

Answers:

Answer

JavaScript has a difference between "method call" and "function call". The former will set this, the latter won't. Syntactically, method call must be of form receiver.method(...args). No dot, no method call. So, this:

document.getElementById(id) // method call, `this` is set to `document`
m = document.getElementById; m(id) // function call, `this` is not set

When you do map(document.getElementById), document.getElementById is a function plucked from its object; when map invokes it, it will invoke it without the receiver, this will not be set, and things get bad.

There is a way to save it: bind, which "methodifies" a function by binding a receiver to it: map(document.getElementById.bind(document)) should work.

EDIT: to further illustrate it:

let foo = {
  bar: function(context) {
    let receiver =
      (this == window) ? "window" :
      (this == foo) ? "foo" :
      "unknown";
    console.log(context + ", `this` is `" + receiver + "`");
  }
}

function call(fn, param) {
  fn(param);
}

foo.bar("In direct call");
let baz = foo.bar; baz("When assigned to a variable");
call(foo.bar, "When passed as a parameter")
let quux = foo.bar.bind(foo); quux("When bound to foo");

Answer

You can if you pass in document to map()'s second this argument, which will provide the correct context for calling getElementById. Not sure if this is an improvement over just using the arrow function, though.

let myArray = ['img1', 'img2', 'img3'].map(document.getElementById, document)

console.log(myArray)
<p id="img1"><p>
<p id="img2"><p>
<p id="img3"><p>

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.