假设我们有一个对象定义为
var 对象 = {计数器:0;增量: function() { this.counter++; } };
现在,调用对象的增量函数将按预期增加计数器。
object.increment();//object.counter 现在等于 1
让我烦恼的是,我会有一个调用参数函数的函数,计数器不会增加,因为 this
变量指向调用函数的闭包。
函数调用(func) { func(); };调用(对象.增量);//object.counter仍然是1
所以我的问题是,是否有任何方法可以使调用者函数保持 this 变量不变,以便 object.counter 在调用时增加所需的效果?
编辑: 由于更深入的解释,更改了接受的答案。
最佳答案
一种思考方式是 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
始终指向同一个调用者。
Note:
bind()
also has the ability to perform partial applications of function parameters, which can also be useful.
因此,我们可以通过以下方式创建增量绑定(bind)函数:
var boundIncrement = counter.increment.bind(counter);
现在,当我们调用 boundIncrement()
时 – 无论实际调用者是谁 – 函数内的 this
都将指向 counter
对象。
boundIncrement() // counter.counter == 1
call(boundIncrement) // counter.counter == 2
理解bind()
为了更详细地理解 bind()
,我们可以纯粹用 JavaScript 实现一个绑定(bind)函数。它看起来像这样:
function bind(fn, invoker) {
return function() {
return fn.apply(invoker, arguments);
}
}
绑定(bind)返回一个函数,该函数将在特定上下文中调用所提供的 fn
,并且始终在该上下文中。
Note: once a function has been bound to a context/invoker, you cannot "undo" that binding. Using
.call()
or.apply()
on a bound function will not changethis
.
另一种方法:对象构造
另一种方法是改变构建 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 中函数如何工作的相同基本概念的不同方式。
关于以对象作为参数的 JavaScript 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20020212/