Why can't I omit the parameter of getElementBy

2020-04-17 03:51发布

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?

2条回答
小情绪 Triste *
2楼-- · 2020-04-17 04:36

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>

查看更多
Melony?
3楼-- · 2020-04-17 04:44

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");

查看更多
登录 后发表回答