Javascript 困惑于何时在事件处理程序中使用“bind”
以下文件已成功打印“foo”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(); })
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中)