每个函数的this是在调用时被绑定的,完全取决于函数的调用位置。
1 默认绑定
function foo()
{
console.log(this); //输出:Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
console.log(this.a); //输出:2
}
var a=2;
foo();
当调用foo()时,this.a被解析成了全局变量a。函数调用时应用了默认绑定,因此this指向全局对象。在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。
function foo()
{
'use strict'
console.log(this); //输出:undefined
console.log(this.a); //Uncaught TypeError: Cannot read property 'a' of undefined
}
var a=2;
foo();
如果使用严格模式(strict mode),则不能将全局对象用于默认绑定,因此this会绑定到undefined。
2 隐式绑定
function foo()
{
console.log(this.a);
}
var obj={
a:2,
foo:foo
}
obj.foo(); //输出:2
当foo()被调用时,它的前面加上了obj的引用,当函数引用有上下文时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因此调用foo()时this被绑定到obj。
var obj={
a:2,
foo:function()
{
console.log(this.a);
}
}
var a='global a';
var bar=obj.foo;
obj.foo(); //输出:2
bar(); //输出:global a
可以看到bar()被调用时,this指向全局对象。bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定,bar是obj.foo的一个引用。
var obj={
a:'obj a',
foo:{
a:'foo a',
bar:function ()
{
console.log(this.a);
}
}
}
var a='global a';
var baz=obj.foo.bar;
obj.foo.bar(); //输出:foo a
baz(); //输出:global a
obj.foo.bar()被调用时,this指向foo,对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。因此obj.foo.bar()调用时输出’foo a’而不是’obj a’。
3 显式绑定
call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。可以通过直接指定this的绑定对象,因此称之为显式绑定。
function foo(b,c)
{
console.log(this.a+b+c);
}
var obj={
a:2
}
var a=1;
foo(3,4); //输出:8 (1+3+4)
//使用call方法
foo.call(obj,3,4); //输出:9 (2+3+4)
//使用apply方法
foo.apply(obj,[3,4]); //输出:9 (2+3+4)
call 和 apply二者的作用完全一样,只是接受参数的方式不太一样。foo.call(obj,3,4); 和foo.apply(obj,[3,4]);调用时this指向obj。
ES5提供了内置的方法Function.Prototype.bind 使用bind(..)会返回一个新函数,它会把指定的参数设置为this的上下文并调用原始函数。
function foo()
{
console.log(this.a);
}
var obj={
a:2
};
var bar=foo.bind(obj);
bar(); //输出:2
如果把null或者undefined作为this的绑定对象传入call、apply、bind.这些值在调用时会被忽略,实际应用的是默认绑定规则。
4 new绑定
1.创建一个全新的对象
2.这个新对象会被执行[[prototype]]连接
3.这个新对象会绑定到函数调用的this
4.如果函数没有返回其他对象,那么new表达式中的函数会自动返回这个新对象
在使用new实例化对象时,this指向这个实例对象。
function foo(a,b)
{
this.a=a;
this.b=b;
}
foo.c=12;
foo.prototype.getSum=function()
{
return this.a+this.b;
}
foo.prototype.getC=function()
{
return this.c;
}
var bar=new foo(2,3);
console.log(bar.a); //输出:2
console.log(bar.b); //输出:3
console.log(bar.c); //输出:undefined
console.log(foo.c); //输出:12
var sum=bar.getSum();
console.log(sum); //输出:5
bar.c=5;
console.log(bar.c); //输出:5
console.log(bar.getC()); //输出:5
执行完上述操作之后的bar

New绑定>显式绑定>隐式绑定>默认绑定
ES6箭头函数
ES6新增了箭头函数,箭头函数不使用this的四种绑定规则,而是根据外层作用域来决定this,且箭头函数的绑定无法被修改。
function foo()
{
return (a)=>{
console.log(this.a);
}
}
function foo1()
{
return function(){
console.log(this.a);
}
}
var obj1={
a:2
};
var obj2={
a:3
};
var bar=foo.call(obj1);
bar.call(obj2); //输出:2
var bar1=foo1.call(obj1);
bar1.call(obj2); //输出:3
参考:你不知道的JavaScript上卷