JavaScript中的this关键字

时间:2021-11-30 03:24:55

在JavaScript中,this通常绑定到函数被调用的对象上,这种默认绑定在多数情况下是正常的,但是在某些情况下,this的这种绑定会丢失,比如,将函数作为参数传递给另外一个函数,这种默认的绑定就丢失了,例如:

var myObj = {
   name: 'A nice demo!',
   fx: function() {
      alert(this.name);
   }
};

function runFx(fx) {
   fx();
}

window.name = 'I am a nice window';

myObj.fx();  // 在这里,将会提示 A nice demo!

runFx(myObj.fx); // 在这里,得到的提示将会是 I am a nice window

为什么会出现这种情况呢?因为在第二次调用中,myObj.fx作为参数传递给了runFx,在函数runFx中执行时fx丢失了对myObj的默认绑定,而绑定到了runFx的默认绑定window上,所以第二次调用时得到的提示为I am a nice window,而这个往往不是我们需要的结果。

在Ajax横行的今天,要编写复杂的客户端组件,不可避免的要将函数名作为参数传递,Prototype注意到了这个问题,MS ASP.Net Ajax也注意到了这个问题,不知道你注意了没有?

Prototype提供的解决方案是bind方法,在Prototype的官方文档给出的描述是:Provides aguaranteed-binding equivalent of the original function, possibly with pre-filled arguments. 上面的例子如果使用Prototype的话,可以修改如下:

var myObj = {
   name: 'A nice demo!',
   fx: function() {
      alert(this.name);
   }
};

function runFx(fx) {
   fx();
}

window.name = 'I am a nice window';

myObj.fx();  // 在这里,将会提示 A nice demo!

var fx2 = myObj.fx.bind(myObj) // 先做一个绑定,
runFx(fx2); // 在这里,得到的提示将会是 A nide demo !这个往往是我们需要的结果

MS Ajax提供的解决方案是Function.createDelegate函数,createDelegate方法是个静态方法,可以直接调用。如果使用MS Ajax库的话,可以将上面的例子修改为:

var myObj = {
   name: 'A nice demo!',
   fx: function() {
      alert(this.name);
   }
};

function runFx(fx) {
   fx();
}

window.name = 'I am a nice window';

myObj.fx();  // 在这里,将会提示 A nice demo!

var fx2 = Function.createDelegate(myObj, myObj.fx) // 按照微软的说法,先做一个委托,
runFx(fx2); // 在这里,得到的提示将会是 A nide demo !这个往往是我们需要的结果

这看起来只是一个小问题,但是如果不注意的话却会造成很大的问题。引用Prototype中的原话:As discussed on the general Function page,binding can be a pretty tricky thing sometimes.