Javascript 困惑于何时在事件处理程序中使用“bind”

Javascript 困惑于何时在事件处理程序中使用“bind”,javascript,this,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(); })

以下文件已成功打印“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
对象。i、 e:

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

那么我们为什么不在第一个示例中使用
bind
。我不知道为什么在匿名函数中包装
obj.printName()
函数调用会导致
控制台.log
正确引用并正确打印
,但在
单击后直接调用时,您需要使用
bind

注意:您需要调用
printButton.addEventListener('click',obj.printName())obj.printName()
中不带括号的code>

答案在于
这个
是用Javascript绑定的。在JS中,函数的调用方式决定了该函数的绑定方式。因此,当您提供如下回调函数时:

printButton.addEventListener('click', function(){
  obj.printName(); 
});
注意,printName是通过
dot
符号调用的。当
绑定到点之前的对象时,这称为隐式绑定规则,在本例中为
obj
。显然,在这种情况下,您得到了预期的输出

但是,当您这样称呼它时:

printButton.addEventListener('click', obj.printName );
请注意,您传递的只是obj内部函数的
地址。因此,在本例中,有关obj的信息丢失。换句话说,调用函数的代码没有关于obj的信息,而obj可以用来设置
。它所拥有的只是要调用的函数的地址

希望这有帮助

编辑: 看看这个我调用的
bind2
实现,它模仿了原生绑定。这只是为了说明本机
bind
函数如何返回新函数

Function.prototype.bind2 = function (context) {
        var callBackFunction = this;//Store the function to call later
        return function () {        //return a new function
            callBackFunction.call(context);//Later when called, apply 
                                           //context, this is `obj` passed 
                                           //in bind2()
        }
    };

    function hello() {
        alert(this.name);
    }
    obj = {
        name:'ABC'
    };
    var f = hello.bind2(obj);


    f();

注意:函数f()在这里是如何硬绑定的。f()具有硬绑定
对象
。您现在不能将
更改为
obj
以外的内容。这是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中:函数正在被调用,因此表达式的值就是函数返回的值。在您的情况下,这是
未定义的


addEventListener
方法
addEventListener
包含两个参数:

  • 事件类型的
    字符串
  • 触发事件时将运行的
    函数
  • 下车,那是什么意思

    当你打电话的时候

    // doesn't work
    printButton.addEventListener('click', obj.printName() );
    
    您没有将
    function
    类型的值传递给
    addEventListener
    方法,而是传递
    undefined

    // works
    printButton.addEventListener('click', obj.printName.bind(obj) );
    
    然后工作(出于一个原因),因为第二个参数的类型实际上是
    function


    bind
    做什么?为什么它返回一个函数? 现在我们需要讨论
    bind
    实际上做了什么。它与指针*
    相关

    *指针是指指向某个对象的引用标识符

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

    下面的示例最能说明这一点:

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

  • boundMethod
    使用了
    bind
  • 未使用绑定的
    unboundMethod
  • 类水果{
    构造函数(){
    this.name='apple';
    }
    printName(){
    console.log(this.name);
    }
    }
    const myFruit=新水果();
    //采用方法`printName`
    const boundMethod=myFruit.printName.bind(myFruit);
    const unboundMethod=myFruit.printName;
    boundMethod();//作品
    
    unboundMethod();//不起作用
    这并不是一个完整的答案,但我想指出一些新的js程序员(有时也是我自己)忘记的事情:函数是一等公民,这意味着1)
    obj.printName
    和2)
    obj.printName()
    之间有区别。1) 此表达式的值是函数本身,这是传递给
    addEventListener
    方法的值。2) 这个表达式调用函数,因此表达式的值就是函数本身返回的值。在本例中,该值是
    未定义的
    。需要注意的另一个可能的重复是,调用bind实际上返回另一个可以调用的函数,如
    obj.printName.bind(obj)(
    printButton.addEventListener('click',obj.printName())
    也将
    obj
    作为
    传递。它只是没有将打印名注册为点击处理程序,它会立即调用它。@melpomene,是的,我认为这是另一个问题,可能是打字错误。他只需要传递函数引用。这不是“上下文”。使用点表示法只是设置函数名称的一种方法,还有许多其他方法(调用、应用、绑定、新建、按词汇在arrow funct中)