从预编译出发,讲解this指向

我们所了解的this指向无外乎是实例自己或window,这里就产生了两个问题,什么情况下指向的实例自己,又在什么情况下指向的window呢?我们会说当new 一个函数时产生的对象,此时的this指向它自己的实例,除此以外的this指向window,看似完美的答案,却经不起进一步的问题,为什么new一个函数的时候this指向自己的实例?如果这个问题弄不清楚的话,在实际写代码过程中就会有迷茫,这就需要我们了解new的时候发生了什么,还有什么情况让this指向window,这里的问题会在以下的讲解过程中找到答案,暂且将这里提到的问题搁置

 

 

运行期上下文

之所以将这里的问题搁置,是因为我要提到一个特别重要的知识点,那就是运行期上下文,这里只是应用其中简单的概念性知识点。

运行期上下文:当函数执行时会创建一个成为执行期上下文的内部对象,这个对象定义了当前函数的执行环境,函数执行时所创建的上下文是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所创建的执行期上下文就立即销毁

函数声明图示:

 

test函数声明时,此时只有一个Global Object(GO),里面的this指向window

test函数执行时,如下:

 

图中的Activation Oject AO)就是一个执行上下文对象,也称作活动对象,它是函数执行时所创建的,如果多次调用一个函数,这样的对象会被多次调用,当函数执行完毕后,这个对象就会销毁。

执行test函数(test())其中AOthisGO里面的this指向的都是window,这里就是预编译决定的;name指定的是各自不同的值,这里是test函数执行时决定的。(这里的test方法执行,可以理解成window.test()

当我们new test()的时候,里面的this就会发生变化

 

 

注意图中AO的变化,this指向已经不是window了(这里可以理解成指向test,这不是严紧的说法)当new test()执行时,test函数里面会设置一个this的值,this指向一个空对象(里面有一个内部字段,我们访问不到),也就是test函数里面多了一个this的变量,值为{}空对象,当执行到this.say时,会在这个{}空对象里面填入this.say=...,形成{this.say=function(){}},最后将这个this返回。

以上就是this指向发生变化的过程

谁调用,this就指向谁

接下来我们说一个比较经常用到的原则【谁调用,this就指向谁】这一原则会受用于许多“规矩”的代码,如下例:

 

function test(){
    this.name='sunqiang'
}
var t=new test();
console.log(t.name);

 

执行t.name,这里是t在调用,所以这里的this指向的就是t,而t恰恰是test 函数new出来的一个实例(test{})实例里面有字段name值为sunqiang

可以这样理解:t=new test();new test()产生test{name:sunqiang}对象

通过上面的讲解过程,我们会推演出this为什么会像网上有些人说的丢失,匿名函数为什么具有全局性。

所谓的this丢失问题例子如下:

var name='sundaqiang';
function test(){
  this.name='sunqiang';
  this.say=function(){
         console.log(this.name);            
  }  
}
var t=new test();
var f=t.say;
console.log(f());

执行结果是:sundaqiang

通过预编译形成如下:

 

函数执行生成的执行期上下文

 

AO里面的say函数赋值给全局变量f,就会形成这样的写法

var f=function(){console.lon(name)};

执行f函数,形成的执行期上下文如下:

 

f() 运行,可以理解成window.f(),本着谁调用,this就指向谁的原则这里的this指向就变成window

执行结果就是:sundaqiang

 

匿名函数具有全局性的例子:

将上面的例子修改下

var name='sundaqiang'
function test(){
  var name='sunqiang';
  return function(){
       console.log(this.name);      
  }      
}
test()();

分析步骤同上,最后test()()执行;

test()执行会产生一个未运行的新函数:funciotn(){this.name}

我们可以这样理解:var f=test(); 再执行f(),那这样f函数里面的this指向就是window

如果这样不明显的话,我们稍做修改

var name='sundaqiang'
function test(){
  this.name='sunqiang';
  return function(){
      console.log(this.name);  
  }      
}
var t=new test();
t();

最后t()执行,本着谁调用,this指向谁的原则,可以将代码理解成 window.t();很明显this指向window

总结

函数的声明,我们需要明确它预编译形成的GO,当函数执行时,我们需要明确它执行时的上下文环境对象AOAO里面字段都有哪些,值又有哪些,最后本着谁调用,this就指向谁的原则确定this的指向,这样一步步下来,我们就清楚自己代码中this是什么了,这无疑是非常重要的,接下来抛出两个问题:怎么改变这个this的指向呢?改变指向的作用有哪些?这些问题我会在今后的博客中有所更新,敬请关注

posted @ 2018-10-29 16:52  七音客  阅读(181)  评论(0)    收藏  举报