JS中的this
this指向的是函数执行的环境对象
注意是对象!
而JS中作用域并不能被看作一个可以被指向的对象
所以无论何时,都不能把this和词法作用域的查找混合使用
比如下面这段代码
var a=1;
function rec(){
var a=2;
alert(this.a);
}
function bar(){
var a=3;
rec();
}
bar();
结果输出的是1
rec函数在bar函数内被调用,但this并不指向bar函数的词法作用域,所以当this向上寻找对象时只找到了全局对象(严格模式则不会找到全局对象) 输出全局对象下的属性a
绑定规则
在函数执行中根据调用位置来决定this指向的对象
有四种规则
默认绑定:无法应用其他规则时的默认方式,比如在全局对象下直接独立调用函数,this就会绑定全局对象(严格模式是undefined)
隐式绑定:调用位置有上下文对象,或被某个对象拥有或包含,比如
对象obj:{a:2,bar:bar}; bar是一个函数,虽然这个函数严格来说并不属于该对象,但调用位置会使用obj上下文来引用函数,所以可以说obj包含了该函数。所以函数内的this指向了obj。
但是隐式绑定常常会丢失this指针的绑定,尤其在回调函数中,比如:
function rec(){
var a=1;
alert(this.a);
}
var a=2;
var obj={
a:3,
rec:rec
};
setTimeout(obj.rec,1000);
最后会输出2,因为在这个例子中,rec函数的真实调用位置是在setTimeout内部,上下文对象是默认的全局对象
显式绑定:应用call()或apply()方法,关于这两个方法:
call和apply作用基本一样用另一个对象替换当前对象,可将一个函数的对象上下文从初始的上下文改变为第一个传入的实参指定的新对象。区别在第二个参数,call()函数是将对象的参数一个个分别传入,apply()函数是将对象的参数以一个数组或arguments对象的形式整体传入。
因此可用bar.apply(obj)来将this指针强制绑定在obj对象上。
为其包裹一个函数名实现在回调函数中应用,来进行硬绑定,:
var baz=function(){
rec.call(obj);};
setTimeout(baz,1000);
用硬绑定来实现一个bind函数
function bind(fn,obj){
return function(){
return fn.apply(obj,arguments);
}
}
function foo(b,c,d){
alert(this.a+b+c+d);
}
var obj={a:4};
var b1=bind(foo,obj);//建立b1函数,作用是把foo函数绑定到obj对象之后,再调用foo函数
b1(1,2,3);//输出为10
内置其实有这个函数,使用方法:var b1=foo.bind(obj);
new绑定:创建一个全新的对象,将其绑定到函数调用的this,如果函数没有返回别的对象,那么就返回这个全新的对象
function foo(a){
this.a=a;
}
var bar=new foo(2);
上面就创建了一个名叫bar的对象,函数的this指向了该对象,所以为其添加了一个属性a,赋值2
上述规则优先级为
new绑定>显式绑定>隐式绑定>默认绑定
可以在硬绑定上再使用new绑定
function plus(a,b){
this.result=a+b;
}
var plus_1=plus.bind(null,1);
var obj=new plus_1(2);
alert(obj.result); //3
这样子做的目的是预先设置好函数的一些参数(bind时)(柯里化),之后再传入剩下的参数(new时)
bind时第一个参数之所以用null是因为之后new会改变this指针指向,所以此时指向什么都无所谓,当然在第一个参数是null或undefined时,会应用默认绑定
所以如果只是想让this指向一个空对象(因为指向全局对象可能会有意想不到的结果)可以创建一个空对象,用Object.create(null),再赋值给apply中的第一个参数