var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}
}
};
alert(object.getNameFunc()()); //"The Window"
object.getNameFunc()返回一个匿名函数,在全局环境调用该函数,this指向的全局对象
解决这一问题,可以像下面这样,将匿名函数外部作用域中this对象保存在闭包能够访问到的变量中
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
}
}
};
alert(object.getNameFunc()()); //"My Object"
上述解决方法需要修改对象的方法,如果不能修改原对象的方法,该如何做呢?
这时,我们可以像下面这样,使用apply或call方法指定函数的作用域
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}
}
};
var func=object.getNameFunc();
alert(func.apply(object)); //"My Object"
通过apply、call,已经可以输出预期的My Object
但是,每次调用时都需要以func.apply(object)的形式调用,这不是很怪么
理想的调用方式,当然是在通过某种处理后,之后可以以func()形式调用,像下面这样
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
}
}
};
var func=object.getNameFunc();
func=func.bind(object);
alert(func()); //"My Object"
ECMAScript 5定了了bind方法,这个方法会创建一个函数实例,其this值会被绑定到传给bind函数的值,上面代码给出了bind函数的使用方式,再给一个简单示例。
window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
}
var func=sayColor.bind(o);
func();//"blue"
虽然大部分浏览器中已经可以使用ECMAScript 5定义的这个方法,但在少数不支持的浏览器中你还是会遇到兼容性问题,这是如何处理呢?
通过上面apply、call方法使用示例 ,可以像下面这样提供一个解决方案
Function.prototype.bind=Function.prototype.bind||
function(context){
var self=this;
return function()
{
return self.apply(context,arguments);
}
}
更改bind参数
如果我们使用变量绑定参数到foo(),然后在调用newFoo()前改变变量,你觉得值会变为什么呢?
function add(a,b){
return a + b;
}
var a = 3;
var b = 4;var newFoo = add.bind(this,a, b);
a = 6;
b = 7;
console.log(newFoo());
返回值仍然是7,因为bind()绑定的是参数的值,而不是实际变量的值。
这是好消息,就像我说的,我们可以在代码中利用这个巨大的优势。但是,对我而言它最有用的地方是在callbacks中。
还记得那篇文章中我们在循环中处理callbacks的解决方案之一就是,围绕我们想要调用的函数创建匿名函数。
但是我们可以使用bind,大大简化代码.
for(var i = 0;i < 10;i++){
setTimeout(console.log.bind(this,i),1000);
}
bind用于事件处理程序
bind()可以让你的代码干净起来的另一个地方是在事件处理程序。大家都知道,或者应该知道,当一个事件处理程序被调用时,它访问的上下文会生成事件,而不是在创建事件处理程序的对象中。通过使用bind,可以肯定的是,函数会被访问正确的上下文。
function ClassName(){
this.eventHandler = (function(){
}).bind(this);
}
Prototype.js中的bind
// The .bind method from Prototype.js
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};