1.让this指向本身的方法
首先this并不是指向本身的,它指向谁取决于它的调用位置。
function classA(num){
console.log('classA'+num);
this.count++;//this的定义位置在classA作用域中
}
classA.count=0;
for(var i=0;i<=10;i++){
if(i>5){
classA(i);//this的调用位置在全局作用域中
}
}
console.log(classA.count);//结果count是全局变量的0
1.1使用词法作用域(在函数内部调用函数本身)
function classA(num){
console.log('classA'+num);
classA.count++;//每次都调用自身的count
}
classA.count=0;
for(var i=0;i<=10;i++){
if(i>5){
classA(i);
}
}
console.log(classA.count);
1.2强制让this指回函数本身(使用了call方法)
function classA(num){
console.log('classA'+num);
this.count++;
}
classA.count=0;
for(var i=0;i<=10;i++){
if(i>5){
classA.call(classA,i);//使用call改变this的上下文,使其指向classA
}
}
console.log(classA.count);
2.this指向谁完全取决于它在什么地方被调用,不取决于它的定义位置,和函数声明的位置没有任何的关系。
2.1怎么找调用位置
调用位置就在当前正在执行的函数的前一个调用中。(调用栈)
2.2函数的执行过程中调用位置如何决定this的绑定对象(绑定规则)
(1)默认绑定
函数直接被调用,没有任何的函数引用来调用它,这时候this绑定的是全局对象。默认绑定无法应用其他规则。
注意:将全局对象用于默认绑定的前提是是在非严格模式下,如果是在严格模式(strict mode )下,this会绑定到undefined。
function foo(){
this.a;
}
foo();//默认绑定:foo直接被调用,这时候this指向全局对象window
(2)隐式绑定
调用位置是否有上下文对象,或者说是否被都个对象拥有或包含。
function foo(){
console.log(this.a);
}
var obj={
a:2,
foo:foo//函数foo被包含在obj对象中
}
obj.foo();//调用位置被将this绑定到foo上下文obj上
注意:隐式绑定可能会丢失绑定的对象,进而应用默认绑定,将this绑定到全局对象或undefined上。
function foo(){
console.log(this.a);
}
function dooFoo(fn){
fn();
}
var obj={
a:2,
foo:foo
}
var a="oops,global",
dooFoo(obj.foo);//oops,global//根据调用位置,被转移成默认绑定
(3)显示绑定(call()和apply())
硬绑定:创建一个函数,并在它的内部手动调用foo.call(obj),因此强制把foo的this绑定到了obj,无论之后如何调用函数bar,它总会手动的在obj上调用foo。例子:
function foo(){
console.log(this.a);
}
var obj={
a=2;
}
var bar={
foo.call(obj);//创建一个bar,手动的将foo的this绑定到obj上。
}
bar();//2
setTimeout(bar,100);//2
//注意硬绑定的bar不可能再修改它的this
bar.call(window);//2
应用场景1:创建一个包裹函数
function foo(something){
console.log(this.a,something);
return this.a+something;
}
var obj={
a:2
};
var bar=function(){
return foo.apply(obj,arguments);//创建一个bar函数,然后将this硬绑定到obj上,并将arguments作为参数传入foo
};
var b=bar(3);
console.log(b);
应用场景2:创建了一个可以重复使用的辅助函数
由于硬绑定是一种非常常用的模式,所以ES5提供内置方法:Function.prototype.bind().
foo.bind(obj);
API调用的“上下文”
(4)new 绑定
new来调用函数的时候(构造函数调用)自动执行下面的操作。
4.1创建一个全新的对象;
4.2这个新对象会被执行[[Prototype]]连接;
4.3这个新对象会绑定到函数调用的this上;
4.4如果函数没有返回其他对象,则new表达式中的函数调用会自动返回这个新对象。
var classA=new ClassA();
其内部的执行过程:
var classA={ };
classA._proto_=ClassA.prototype;
ClassA.call(classA);
this绑定的优先级:
new绑定>显示绑定>隐式绑定>默认绑定