在 JavaScript 中,函数通常运行在一个特定的上下文中(通常称为“作用域[scope]”)。在函数内部, this
关键字是指向那个作用域的引用。实际上,每个函数都是对象的属性——全局函数是 window
对象的属性——运行时函数的作用域即为函数被调用时函数所属的对象, 更严格的说法是保存了对函数的引用的对象:
window.name = "the window object";
function scopeTest() {
return this.name
}
// 在全局作用域内调用这个函数:
scopeTest()
// -> "the window object"
var foo = {
name: "the foo object!",
otherScopeTest: function() {
return this.name
}
}
foo.otherScopeTest()
// -> "the foo object!"
因为动态语言的特性,我们不能确保函数总是被同一种类型的对象调用,如 otherScoptTest()
也可以被 foo
之外的对象调用。这时,函数的 this
引用也会指向其它的对象,例如 window
对象:
// ... 继续上面的样例
// 注意,我们不是调用这个函数,而是简单引用它
window.test = foo.otherScopeTest
// 现在实际调用这个函数
test()
// -> "the window object"
最后那个调用证明了同样的函数具有不同的行为,它依赖于运行时的作用域。
当你在代码中将函数的引用赋给另外一个对象时,通常会希望函数运行在一个固定的作用域中。在 Prototype 中, 只要在函数上调用 bind
方法,将 this
关键字绑定到你所指定的对象, 就可以确保函数运行在期望的作用域中。如果需要的话,你也可以保存返回的函数,以重复使用它。
样例
下面的代码是关于上述概念的一个简单证明:
var obj = {
name: 'A nice demo',
fx: function() {
alert(this.name);
}
};
window.name = 'I am such a beautiful window!';
function runFx(f) {
f();
}
var fx2 = obj.fx.bind(obj);
runFx(obj.fx);
runFx(fx2);
目前,仅有少数人知道:
bind
也可以用来为最终的参数列表预设参数值:
var obj = {
name: 'A nice demo',
fx: function() {
alert(this.name + '\n' + $A(arguments).join(', '));
}
};
var fx2 = obj.fx.bind(obj, 1, 2, 3);
fx2(4, 5);
// 显示相应的 name 值,及 "1, 2, 3, 4, 5"