【问题标题】:addEventListener, arrow functions, and `this` [duplicate]addEventListener、箭头函数和`this` [重复]
【发布时间】:2023-03-15 05:58:01
【问题描述】:

我正在经历 JavaScript30 挑战,在 lesson 3 中,他有一些事件监听器调用一个函数,该函数引用它作为 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));

我正在尝试使用 ES6 箭头函数重写它,但我无法让 this 正常工作。我有一个使用target 的解决方法:

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

但我首先尝试像这样绑定函数:

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

但是函数内部的this仍然指向window,我不明白为什么。

在这种情况下是否没有“正确”的方式将函数绑定到元素?

【问题讨论】:

  • 如果你想使用this那么你需要使用常规函数。箭头函数不能真正与 this 一起正常工作。
  • 另外,有没有正确的方法来使用箭头函数呢? 没有
  • 我想我记得读过一些东西说或建议,明确编写箭头函数是为了避免影响“this”。
  • 普通函数和thise.currentTarget(不是e.target!!)
  • 箭头函数只允许从定义它们的环境继承'this'的值,而不是它们被调用的上下文。演示代码使用常规函数,'this'引用调用它的环境。根据定义,箭头函数不可能做到这一点,因此为什么不能在需要使用“this”的任何地方使用它们。

标签: javascript this


【解决方案1】:

这是什么?

this是Javascript中的一个特殊关键字,指的是函数的执行环境:

  • 如果在全局范围内执行函数,this 将绑定到窗口
  • 如果将函数传递给事件处理程序的回调,this 将绑定到引发事件的 DOM 元素

绑定

bind 方法基本上是说,当你调用函数时,用我的参数替换它。所以,例如:

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)

此外,箭头函数只是将函数的this 绑定到this 的当前值的语法糖。例如,

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

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

(基本上,我知道这是过于简单化了)

你的困境

在正常的事件过程中(不使用箭头函数),this 绑定到 DOM 元素。

当您执行创建事件处理程序input.addEventListener('change', handleUpdate.bind(this)); 时,您正在全局范围内运行(所以this === window)。所以你有效地运行input.addEventListener('change', handleUpdate.bind(window));(这是你注意到的行为)。而使用箭头函数也是一样的。

如果你想用匿名函数替换回调,你应该这样做:

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

【讨论】:

  • 箭头函数没有this的概念。 this 在箭头函数内部是 this 在其包含的词法环境中的任何内容。
  • 因此“我知道这是过于简单化了”。我认为当有人刚刚学习 JS 时尝试讨论词汇范围可能不是最好的教学方法。如果您正在阅读本文并想要更正确的解释:箭头函数不绑定 this 所以 this 只是指它在封闭词法范围中引用的任何内容。但是,如果他们刚刚将其绑定到封闭范围,这在功能上是相同的。
  • 关键是你的整个答案可以替换为“箭头函数没有这个概念。箭头函数内部的 this 是它们包含的词法环境中的任何内容。不要使用箭头函数如果你需要绑定this的值。"可能还有一些对 ECMAScript 2015 语言规范的引用。
  • 这无法解释为什么他对 .bind 的尝试不起作用
  • 这绝对可以解释为什么他的绑定尝试不起作用“箭头函数没有 this 的概念。箭头函数内部的 this 是它们包含的词法环境中的 this 。不要如果需要绑定 this 的值,请使用箭头函数。"