随着使用模式的复杂,显示传递会让代码越来越混乱,this可以将API设计的更加简洁易于复用。

误解-指向自身

举个例子说明this其实并不是我们所想的指向函数本身的

1
2
3
4
5
6
7
8
9
10
11
function foo(num){
console.log('foo:'+num);
this.count++;
}
foo.count=0;
for(var i=0;i<10;i++){
if(i<6){
foo(i);
}
}
console.log(foo.count); //0

console.log产生了6条输出,证明foo调用了6次,但是foo.count仍然是0,显然理解是错误的
解决办法:将if里的代码修改成foo.call(foo,i)

误解-作用域

this指向函数的作用域,某特定情况对,别的情况都错误。
但是this在任何情况下都不指向函数的词法作用域(存在于引擎内部)。

this

this是在运行时绑定的,它的上下文取决于函数调用的各种条件。它的绑定和函数声明的位置没有关系,只取决于函数的调用方式。

绑定规则

默认绑定,隐式绑定

默认绑定:函数调用时应用了this的默认绑定,因此this指向全局。foo是直接调用的,只能是默认绑定。严格模式下,全局对象无法使用默认绑定,this会绑到undefined
隐式绑定:通常对象内部有个指向函数的属性,来间接引用函数

1
2
3
4
5
6
7
8
9
10
11
function foo(){
console.log(this.a);
}
var bar={
foo:foo,
a:2
};
var baz=bar.foo;
var a=3;
baz(); //3
bar.foo(); //2

此处baz()其实是引用了foo(),而不是引用bar.foo,所以是默认绑定
而bar.foo()就是典型的隐式绑定

显示绑定

利用call/apply,第一位传入要指向的对象(差别在后面传的参数,比如foo.call(null,1,2,3) foo.apply(null,[1,2,3]))
这样依旧不能解决this丢失的问题,所以——硬绑定:

1
2
3
4
5
6
7
8
9
function foo(something){
console.log(this.a,something);
return something+this.a;
}
var obj={
a:2
}
var bar=foo.bind(obj);
bar(3); //2,3

bind会返回一个硬编码的新函数,会把参数设置为this的上下文并调用原始函数。

new绑定

new调用,其实是函数的“构造调用”,并非构造函数。

1
2
3
4
5
function foo(a){
this.look=a;
}
var bar=new foo(2);
console.log(bar.look); //2

调用的是个function,new出来的是个object,把new出来的新对象绑定到foo()中的this上。

优先级

除去例外,优先级顺序是:
new->call/apply/bind(显示)->隐式->默认