javascript 的函数在执行期间才会确定他的context,也就是说this在此时被赋值。
但是你常常遇到这种情况
function process(){
this.name = "hello";
document.onclick = function(){
alert(this.name);
}
}
var p = new process();
-------------------------------------
上面这个 程序执行之后,你在页面上“点击”,你期待出现的是 “hello”,实际的结果是 undefined;
1问题来了,this.name 怎么会没定义呢, 仔细看下发现 ,点击时,执行了函数 那么此时的context是什么呢,this 自然就是document,但是document没有name属性,自然就是没定义了。
2 你期待的结果是什么呢 弹出 “hello”
怎么解决呢
(1)既然执行函数时this赋值,我们不使用this 不就完了
function process(){
var self = this;
this.name = "hello";
document.onclick = function(){
alert(self.name);
}
(2) 还想使用this ES5 中使用了一个bind方法,可以实现这个
document.onclick = function(){
alert(this.name);
}.bind(this);
但是这里有个问题,就是bind 函数只能针对 expression的函数声明,对于declaration的 没有此函数
并且并不是所有的浏览器都支持这个方法。
跨浏览器的做法
Function.prototype.bind = Function.prototype.bind || function(th){
var func = this;
return function(){
func.apply(th,[].slice.call(arguments));
}
}
(3) 还有一种方法,我们可以利用一个工具函数,专门的导入这个this,保持this的上下文一致
function fixThis(func,th){
return function(){
return func.apply(th);
}
}
上面的点击可以写成
document.onclick = fixThis(function(){
alert(this.name);
},this);
----------------------------------------
早期绑定有个问题是,当你遇到继承的情况
function preBind(func,th){
return function(){
func.apply(th,[].slice.call(arguments));
}
}
function Animal(){
this.type = function(){
alert("Animal");
}
document.onclick = preBind(this.type,this);
}
function Cat(){
Animal.call(this);//继承 Animal
this.type = function(){
alert("cat");
}
}
//执行
new Cat();
你期待的结果是,点击之后,出现“cat” 但是实际的结果是 “Animal”,问题出在哪里呢
问题出在这里 document.onclick = preBind(this.type,this); 这个函数是在 Animal 里面注册的,
当 继承时,即执行preBind() 函数,返回一个闭包,此闭包的环境hold住的弹出内容的方法体是 “Animal"那个
如何解决呢, 把早期绑定的内容 换成,下面这个,后期绑定,执行时根据具体的环境决定那个函数被调用。
function postBind(str,th){
return function(){
return th[str].apply(th,[].slice.call(arguments));
}
}