假设我们有一个定义为
的对象 var object = {counter: 0; increment: function() { this.counter++; } };
现在,调用对象的递增函数将按预期增加计数器。
object.increment(); //object.counter will now equal to 1
我的错误是我会有一个调用参数函数的函数,计数器不会递增,因为this
变量指向调用函数的闭包。
function call(func) { func(); }; call(object.increment); //object.counter still 1
所以我的问题是,是否有任何方法可以使调用函数保持此变量不变,以便在调用时增加object.counter的效果?
编辑: 由于更深入的解释,改变了已接受的答案。
答案 0 :(得分:3)
考虑它的一种方法是JavaScript中的this
关键字不对定义的对象的引用,但引用当前的调用者 - 正在进行调用的对象。考虑一下你的例子:
var counter = {counter: 0; increment: function() { this.counter++; } };
如果我们要构建另一个具有相似形式的对象,我们可以“借用”increment
函数:
var startAt100 = {counter:100, increment: counter.increment }
startAt100.increment()
// startAt100.counter == 101
这里,因为startAt100
对象正在进行调用,所以函数this
内部引用startAt100
。
解决此问题的一种方法是使用bind()
功能。 bind()
函数接受一个函数并返回该函数的一个版本,其中this
始终指向同一个调用者。
注意:
bind()
还能够执行函数参数的部分应用程序,这也很有用。
因此,我们可以通过执行以下操作来创建增量的绑定函数:
var boundIncrement = counter.increment.bind(counter);
现在,当我们调用boundIncrement()
时 - 无论实际调用者是谁 - 函数内的this
都会指向counter
对象。
boundIncrement() // counter.counter == 1
call(boundIncrement) // counter.counter == 2
bind()
为了更详细地理解bind()
,我们可以纯粹在javascript中实现一个绑定函数。它看起来像这样:
function bind(fn, invoker) {
return function() {
return fn.apply(invoker, arguments);
}
}
Binding返回一个函数,该函数将在特定的上下文中调用提供的fn
,并始终在该上下文中。
注意:一旦函数绑定到上下文/调用者,您就无法“撤消”该绑定。在绑定函数上使用
.call()
或.apply()
不会更改this
。
另一种方法是改变构建counter
对象的方式。我们可以使用匿名函数来创建一个稳定的作用域,然后创建一个引用该作用域中的变量的闭包。通过这样做,您可以创建一个具有稳定执行环境的函数,而不是使用this
。请考虑以下代码:
var counter = (function() {
var state = { counter: 0 }
state.increment = function() { state.counter += 1; };
return state;
})();
counter.increment() // counter.counter == 1
call(counter.increment); // counter.counter == 2
现在,当您调用counter.increment()
时,由于state
已经创建了函数,因此将始终指向并变异该特定对象。
这不是更好或更糟,只是一种不同的方式来理解函数如何在JavaScript中工作的相同基础概念。
答案 1 :(得分:1)
您可以使用.bind()
:
call(object.increment.bind(object));
如果您必须支持没有.bind()
的旧运行时环境,您可以将其包装在函数中:
call(function() { object.increment(); });