一、前言

this是前端开发人员绕不过来的一个点,而this的指向有总是让咱们很头疼,明天就让咱们一起来彻底踩碎this相干问题吧。

二、this的作用

很多人会说this这么厌恶,为什么咱们须要它呢,其实this在代码外面是起到了十分大的作用的,简略来说,this提供了一种更优雅的形式来隐式“传递”一个对象援用,因而就能够将API设计得更加简洁并且易于复用。随着你的应用模式越来越简单,显示传递上下文对象会让代码变得越来越凌乱,应用this则不会这样。

三、this到底指向谁

总体来说,this有四条绑定规定,当你遇到一个this,你只须要看看它合乎那条规定,而后就能找到对应的指向,听起来是不是很简略呢?
四条规定如下:

1. 默认绑定:非严格模式下指向全局对象,严格模式下指向undefined。

独立函数调用无奈实用其余规定,所有它被认为是默认绑定,比方:

function foo(){    console.log(this.a)}var a = 1;foo();   //1
严格模式下,独立函数调用的this是指向undefined的。须要留神的是,决定this绑定对象的并不是函数的调用地位是否处于严格模式中,而是函数体是否处于严格模式中。

2. 隐式绑定:当函数调用地位领有上下文对象的时候,隐式绑定规定会将函数调用中的this绑定到这个对象上(留神有隐式失落的状况)

隐式绑定应该是最常见也最令人头疼的了,不过当初咱们晓得了规定,只有找打了上下文对象,就能够轻松的找到this到底指向谁啦。

 function foo(){     console.log(this.a)  }  var obj = {      a:2,      foo:foo };  obj.foo();//2

在这个例子中,咱们能够说函数被调用时,obj对象“领有”或者“蕴含”它,此时obj就是函数的上下文,this.a也就相当于obj.a。

对象属性援用链中只有上一层或者说最初一层在调用地位中起作用。(能够了解为就近准则)
举例:

 function foo(){     console.log(this.a)  }  var obj2 = {      a:2,      foo:foo };var obj1 = {      a:1,      obj2:obj2 };obj1.obj2.foo();  //2
联合第1、2两条规定,咱们能够简略的总结为,函数执行时首先看函数名后面是否有".",有的话,"."后面是谁,this就是谁;没有的话this就是window
值得注意的是隐式失落的状况:

隐式失落是指被隐式绑定的函数会失落绑定对象,从而利用默认绑定规定的状况。
最常见的例子就是当你把一个函数传入语言内置的函数的时候,就会产生隐式失落。比方常见的setTimeout:

function foo(){     console.log(this.a) } var obj = {     a:2,     foo:foo } var a = "global" setTimeout(obj.foo,100);//global

此时foo函数内的this并不是执行obj的,而是利用了默认规定,指向了全局对象,是不是很意外?这是为什么呢?让咱们来看一看内置setTimeout函数实现的伪代码吧:

 function setTimeout(fn,delay){     fn();  }

看到没,其实传入的函数其实是独立调用的,所以应用了默认绑定规定。
隐式失落最常见的就是产生在回调函数中,大家要特地留神哦

3. 显示绑定:通过call(..)和apply(..)等办法本人显示的指定this的指向。

4. new绑定:this指向新结构进去的对象。

应用new来调用函数,或者说产生结构函数调用时,产生了哪几步?

1.创立一个新对象

2.将构造函数的对象赋给新对象(因而this就指向了这个新对象)

3.执行构造函数中的代码(为新对象增加属性)

4.返回新对象

--《javascript高级程序设计》

从下面的步骤来看,有一步就是:将构造函数的对象赋给新对象(因而this就指向了这个新对象)
举个例子:

function foo(a){     this.a = a; } var bar = new foo(2); console.log(bar.a);//2

应用new来调用foo()时,咱们会结构一个新对象bar,并把它绑定到foo()调用中的this上。

四、上述四条规定的优先级

1.函数是否在new中调用(new绑定) ? 如果是的话this绑定的是新创建的对象

2.函数是否通过call、apply(显式绑定)或者硬绑定调用 ? 如果是的话,this绑定的是指定的对象

3.函数是否在某个上下文对象中调用(隐式绑定) ? 如果是的话,this绑定的是那个上下文对象

4.如果都不是的话,应用默认绑定,严格模式下,绑定到undefined,非严格模式下,绑定到全局对象

每看到一个this咱们只须要通过上述步骤一步一步的走下来,便能很轻松的找到它的指向了,是不是很轻松呢?

五、非凡状况

1.箭头函数:

箭头函数没有本人的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this。
换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是外部箭头函数的this,如果没有,则this是window

2.间接援用:

 function foo(){     console.log(this.a)  }  var a = 2;  var o =  {     a:3,     foo:foo };  var p = {a:4};  o.foo();//3  (p.foo = o.foo)();//2

赋值表达式p.foo=o.foo的返回值是指标函数的援用。

六、this总结

1.this既不指向本身,也不指向函数的词法作用域。

2.this实际上是在函数被调用时产生的绑定,它指向什么齐全取决于函数在哪里调用
因为确定this的指向是在执行上下文的创立阶段实现的,而执行上下文的创立阶段位于函数被调用但未执行任何外部函数的时候,也就是说在函数调用的时候才决定了this的指向---箭头函数是例外

七、参考

《你不晓得的JavaScript》(上卷)
《javascript高级程序设计》