当调用一个函数时(激活),一个新的执行上下文就会被创建。而一个执行上下文的生命周期可以分为两个阶段。
- 创建阶段
在这个阶段中,执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向。
- 代码执行阶段
创建完成之后,就会开始执行代码,这个时候,会完成变量赋值,函数引用,以及执行其他代码。
变量对象(Variable Object)
变量对象的创建,依次经历了以下几个过程。
-
建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。
-
检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
-
检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改。
作用域与作用域链
JavaScript代码的整个执行过程,分为两个阶段,代码编译阶段与代码执行阶段。编译阶段由编译器完成,将代码翻译成可执行代码,这个阶段作用域规则会确定。执行阶段由引擎完成,主要任务是执行可执行代码,执行上下文在这个阶段创建。
作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找。ES5中主要有全局作用域、函数作用域、(eval);
作用域链是在函数执行上下文创建阶段确定的,它是作用域具体实现。
函数在调用激活时,会开始创建对应的执行上下文,在执行上下文生成的过程中,活动对象,作用域链,以及this的值会分别被确定。
this确定
this的指向,是在函数被调用的时候确定的。也就是执行上下文被创建时确定的。
在chrome中调试
'use strict'; | /* 'use strict'; */ |
执行2之前
:
|
执行2之前:
|
执行15,即进入函数foo():
|
执行到7 c:this.a+20;报错!
原因:this指向undefine,而undefined没有任何属性!
|
|
|
this的指向,是在函数被调用的时候确定的。
在函数执行过程中,this一旦被确定,就不可更改了。
如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。如果函数独立调用,那么该函数内部的this,则指向undefined。但是在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
从结论中我们可以看出,想要准确确定this指向,找到函数的调用者以及区分他是否是独立调用就变得十分关键。