2

When using bind() on an Event Listener in JavaScript I can no longer get the element with "this".

Here is my code:

function callback(){

     console.log(this.someVar);
     // Works fine

     console.log(this);
     // No longer refers to the element, outputs "Object"

}

callback = callback.bind({someVar: 1234});

element.addEventListener('click', callback);

Any idea on how to fix this?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Ood
  • 1,445
  • 4
  • 23
  • 43

4 Answers4

2

If you want to pass one variable but keep the this context, then you can use currying or partial application:

Curry

Your function has to receive a value and return another function. This way you can do the following:

function callback(num) {
  return function() {
    console.log(num);
    console.log(this.id);
  }
}

var number = 1;

document.getElementById("hello").addEventListener("click", callback(number));

//change the variable
number = 2;
document.getElementById("world").addEventListener("click", callback(number));

//change the variable again
number = 3;
<button id="hello">Hello</button>
<button id="world">World</button>

Partial application

Same idea but instead of having your callback return a new function, it will just take a single argument and work normally, you need another function that will do the partial application:

function callback(num) {
  console.log(num);
  console.log(this.id);
}

var number = 1;

document.getElementById("hello").addEventListener("click", partial(callback, number));

//change the variable
number = 2;
document.getElementById("world").addEventListener("click", partial(callback, number));

//change the variable again
number = 3;


function partial(fn, arg) {
  return function() {
    return fn.call(this, arg);
  }
}
<button id="hello">Hello</button>
<button id="world">World</button>

The partial application function can be generalised to handle any amount or arguments

In ES6:

function partial(fn, ...args) {
  return function(...otherArgs) {
    return fn.apply(this, [...args, ...otherArgs]);
  }
}

In ES5:

function partial(fn) {
  var args = [].prototype.slice.call(arguments, 1);
  return function() {
    var otherArgs = [].[].prototype.slice.call(arguments);
    return fn.apply(this, args.concat(otherArgs));
  }
}
Community
  • 1
  • 1
VLAZ
  • 26,331
  • 9
  • 49
  • 67
1

The bind() method creates a new function that, when called, has its this keyword set to the provided value.

So, when you call a function like

callback = callback.bind({someVar:1234})

this inside the function callback will be the object {someVar:1234}

To access someVar in the callback function, you have to use this.someVar.

I hope this helps.

If you are still unclear refer this article https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

Kalesh Kaladharan
  • 1,038
  • 1
  • 8
  • 26
1

You can still use event.target and can get access to the clicked element.

function callback(event){

 console.log(this.someVar);
 // Works fine

 console.log(event.target);
 // No longer refers to the element, outputs "Object"

}

callback = callback.bind({someVar: 1234});

element.addEventListener('click', callback);
0

You can call bind() only once. After bind() called, this reference is bind to the argument. So the even can not be assigned to this. For example:

function f() {return this;}
f = f.bind({a:1});
f(); // => {a:1}
f = f.bind({a:2}); // this is what addEventListener actually do as if it bind this to even
f(); // {a:1}

addEventListener cannot bind this again.

lazyboy
  • 301
  • 3
  • 12
  • You can call `bind` multiple times. Even if you call it on a bound function, you can perform partial application. – VLAZ Nov 02 '19 at 21:04
  • I means in context of `callback = callback.bind({someVar: 1234});` – lazyboy Nov 02 '19 at 21:10