以下成功打印'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
答案 0 :(得分:1)
好吧,我在这个问题上评论了一些很好的信息,所以我不妨回答一下!
好的,让我们从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
相关。
* by pointer,我指的是某个对象的引用标识符
bind
是一个存在于每个函数对象上的方法,它只是将所需对象的this
指针绑定到函数
最好通过一个例子来说明:
假设您有一个类Fruit
,其方法为printName
。现在我们知道您可以将方法保存到变量中,让我们尝试一下。在下面的示例中,我们分配了两件事:
boundMethod
的bind
unboundMethod
没有使用bind
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
时会发生什么?为什么这不起作用?
如果您在这种情况下不调用bind,则可以将存储到标识符unboundMethod
中的函数的值视为:
// doens't work
const unboundMethod = function() {
console.log(this.name);
}
其中函数的内容与printName
类中的方法Fruit
的内容相同。你知道为什么这是一个问题吗?
因为this
指针仍在那里,但它想要引用的对象不再在范围内。当你尝试调用unboundMethod
时,你&# 39;我会收到错误,因为它无法在name
中找到this
。
那么当您使用bind
时会发生什么?
松散 bind
可以被视为将this
函数的值替换为您传入bind
的对象。
因此,如果我将myFruit.printName.bind(myFruit)
分配给boundMethod
,那么您可以将此类作业视为:
// works
const boundMethod = function() {
console.log(myFruit.name);
}
其中this
替换为myFruit
何时在事件处理程序中使用
bind
如果要将函数内的this
es替换为另一个对象/指针,则需要使用Function.prototype.bind
。 如果您的功能没有使用this
,那么您就不需要使用bind
。
为什么我们不需要在第一个例子中使用bind?
如果您不需要采取方法" (即取function
类型的值),那么你就不需要使用bind
另一种说法是:如果你直接从对象,你不需要bind
同一个对象。
在包装函数中,您直接调用对象的方法(如表达式2)。因为您在没有"采取方法的情况下调用该方法" (我们"将方法转换为Fruit示例中的变量),您不需要使用bind
。
printButton.addEventListener('click', function(){
// directly invoke the function
// no method "taking" here
obj.printName();
});
希望这会有所帮助:D
答案 1 :(得分:0)
注意:您需要在2
中调用printButton.addEventListener('click', obj.printName() );
不带括号,因为您要传递该功能。
答案在于obj.printName()
在Javascript中绑定的方式。在JS中,调用函数的方式决定了this
的绑定方式。所以当你提供如下的回调函数时:
this
注意,printName是通过printButton.addEventListener('click', function(){
obj.printName();
});
表示法调用的。当dot
绑定到点之前的对象时,这称为隐式绑定规则,在本例中为this
。显然,在这种情况下,您可以获得预期的输出。
但是,当你这样称呼它时:
obj
请注意,您传递的所有内容都是obj内部函数的printButton.addEventListener('click', obj.printName );
。所以在这种情况下,关于obj的信息丢失了。换句话说,回调函数的代码没有关于可能用于设置address
的obj的信息。它只是要调用的函数的地址。
希望这有帮助!
修改强>:
看看我称之为模仿本机绑定的this
的{{1}}实现。这只是为了说明native crude
函数如何返回一个新函数。
bind2
注意:函数f()在这里是bind
的方式。 f()与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();
具有硬绑定hard bound
。您现在无法将this
更改为obj
以外的其他人。这是绑定的另一件事,可能会帮助你了解。