addEventListener, arrow functions, and `this` [duplicate]

只谈情不闲聊 提交于 2020-04-06 06:49:48

问题


I'm going through the JavaScript30 challenge, and in lesson 3 he's got some event listener calling a function that references the element it's called on as this:

const inputs = document.querySelectorAll('.controls input');
function handleUpdate() {
  const suffix = this.dataset.sizing || '';
  document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
}
inputs.forEach(input => input.addEventListener('change', handleUpdate));
inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

I'm trying to rewrite it with ES6 arrow function, but I can't get the this to work right. I got a workaround using target:

const handleUpdate = (e) => {
  const that = e.target;
  const newValue = `${that.value}${that.dataset.sizing || ''}`;
  etc.
}

but I first tried to bind the function like that:

input.addEventListener('change', handleUpdate.bind(this));

But this inside the function still points to window and I don't understand why.

Is there no "right" way to bind the function to the element in this case?


回答1:


What is this?

this is a special keyword in Javascript that refers to the executing environment of the function:

  • If you execute a function in the global scope, this will be bound to the window
  • If you pass the function to a callback for an event handler, this will be bound to the DOM element that raised the event

Binding

The bind method basically says, when you call the function, replace this with whatever my argument is. So, for example:

let a = {}
function test_this() {
     return this === a;
}  

test_this(); // false
test_this.bind(a)(); // true (.bind() returns the bound function so we need to call the bound function to see the result)

Additionally arrow functions are simply syntactic sugar for binding the function's this to the current value of this. For example,

let b = () => { /* stuff */ }

is the same as

let b = (function () { /* stuff */}).bind(this);

(basically, I know this is an oversimplication)

Your predicament

In the normal course of events (not using arrow functions), this is bound to the DOM element.

When you're executing the creation of the event handler input.addEventListener('change', handleUpdate.bind(this)); you're running in the global scope (so this === window). So you're effectively running input.addEventListener('change', handleUpdate.bind(window)); (which is the behavior you're noticing). And using the arrow function is the same thing.

If you want to replace the callback with an anonymous function you should instead do:

const handleUpdate = function (e) {
  const that = e.target;
  const newValue = `${that.value}${that.dataset.sizing || ''}`;
  // etc.
}


来源:https://stackoverflow.com/questions/41914596/addeventlistener-arrow-functions-and-this

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!