javascript - 对于何时在事件处理程序中使用`bind`感到困惑

标签 javascript this

以下代码成功打印出“ foo”。

var obj = {
    name: 'foo',
    printName: function printName() {
      console.log(this.name);
    }
  };

var printButton= document.getElementById('printIt');

printButton.addEventListener('click', function(){
  obj.printName(); 
});


但是,以下内容不是:

printButton.addEventListener('click', obj.printName() );


我知道解决方案...只需使用bind,以便我们引用obj对象。即:

printButton.addEventListener('click', obj.printName.bind(obj) );


为什么然后在第一个示例中不需要使用bind呢?我不知道为什么在匿名函数中包装obj.printName()函数调用会导致console.log正确引用和正确打印this,但是当直接在click之后调用时,您需要使用bind

最佳答案

好了,我在这个问题上评论了一些很好的信息,所以我不妨回答!

功能是一流的

好的,让我们从与其他编程语言非常不同的javascript基础开始:在javascript函数中,一等公民是一流的公民-这只是一种说法,可以将函数保存到变量中,也可以将函数传递给其他函数功能。

const myFunction = function () { return 'whoa a function'; }
array.map(function () { return x + 1; });


并且由于这个奇妙的功能,表达式之间有很大的区别:

表达式1

obj.printName




表达式2

obj.printName();


在表达式1中:该函数没有被调用,所以表达式的值是function类型

在表达式2中:该函数正在被调用,因此表达式的值就是该函数返回的值。就您而言,这是undefined



addEventListener

方法addEventListener带有两个参数:


事件类型的string
事件触发时将运行的function


下车,那是什么意思?

您打电话的时候

// doesn't work
printButton.addEventListener('click', obj.printName() );


您没有将类型function的值传递给addEventListener方法,实际上是在传递undefined

// works
printButton.addEventListener('click', obj.printName.bind(obj) );


然后起作用(由于一个原因),因为第二个参数实际上是function类型。



bind是做什么的?为什么返回一个函数?

现在我们需要讨论bind的实际作用。它与指针* this有关。

*通过指针,我的意思是指向某个对象的引用标识符

bind是存在于每个函数对象上的一种方法,该方法仅将所需对象的this指针绑定到函数

最好通过一个示例来说明:

假设您有一个具有方法Fruit的类printName。现在我们知道您可以将方法保存到变量中,让我们尝试一下。在下面的示例中,我们分配了两件事:


使用boundMethodbind
没有使用unboundMethodbind




class Fruit {
  constructor() {
    this.name = 'apple';
  }
  
  printName() {
    console.log(this.name);
  }
}

const myFruit = new Fruit();

// take the method `printName`
const boundMethod = myFruit.printName.bind(myFruit);
const unboundMethod = myFruit.printName;

boundMethod(); // works
unboundMethod(); // doesn't work





那么,当您不拨打bind时会发生什么呢?为什么不起作用?

如果在这种情况下不调用绑定,则可以将存储在标识符unboundMethod中的函数的值视为:

// doens't work
const unboundMethod = function() {
    console.log(this.name);
}


其中函数的内容与printName类中的方法Fruit的内容相同。您知道为什么这是一个问题吗?

因为this指针仍然存在,但是原本打算引用的对象不在范围内。尝试调用unboundMethod时,会出现错误,因为它在name中找不到this

那么当您使用bind时会发生什么呢?

松散地将bind视为将函数的this值替换为要传递给bind的对象。

因此,如果我将myFruit.printName.bind(myFruit)分配给boundMethod,则可以想到这样的分配:

// works
const boundMethod = function() {
    console.log(myFruit.name);
}


其中this被替换为myFruit

底线/ TL; DR


  何时在事件处理程序中使用bind


要将函数内的Function.prototype.bind替换为另一个对象/指针时,需要使用this。如果您的函数从不使用this,则无需使用bind


  那么为什么在第一个示例中我们不需要使用bind?


如果您不需要“采用方法”(即采用function类型的值),那么您也不需要使用bind另一种写法是:如果您直接调用方法从对象中,您不需要bind相同的对象。

在包装函数中,您将直接调用对象的方法(如表达式2中所示)。因为您在调用方法时没有“采用方法”(在“水果”示例中将方法“放入”变量中),所以不需要使用bind

printButton.addEventListener('click', function(){
  // directly invoke the function
  // no method "taking" here
  obj.printName();
});


希望这会有所帮助:D

关于javascript - 对于何时在事件处理程序中使用`bind`感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43829225/

相关文章:

javascript - 在 onclick 事件上动态更改按钮功能

javascript - 在创建实例后通过 JavaScript 更新 CKEditor 的 CSS

c++ - 用于提高回调注册可读性的宏

javascript - 如何从 JavaScript 中的匿名事件监听器访问对象属性

javascript - 从 2.7.x 升级到 2.8.x 后出现 TypeScript 错误 TS2349

javascript - 在特定 Node 版本上运行应用程序

c++ - 在派生类中调用 sizeof(*this)

java - this 在 equals 方法中

JavaScript 命名空间和 jQuery 事件处理程序

javascript - JavaScript 中的简单复制粘贴功能