关键词:
执行上下文、词法环境、变量环境、this、执行上下文栈、变量对象、做用域链javascript
执行上下文定义了变量或函数有权访问的其余数据,决定了他们各自的行为。当javascript代码执行一段可执行代码时,会建立对应的执行上下文; 代码所有执行完后,该执行上下文也会被销毁,保存在其中的变量和函数定义也随之被销毁。执行上下文会管理代码执行过程当中使用的内存。前端
执行上下文分3种:java
javascript引擎建立执行上下文有两个阶段:web
在全局执行上下文中,this指向全局对象(浏览器中指window对象);
在函数执行上下文中,this的值取决于函数是如何并调用的。若是函数被一个引用对象调用,那么this会被设置成这个对象,不然this会被设置为window或undefined(严格模式下)浏览器
var obj = {
getThis: function(){
return this
}
}
obj.getThis(); // obj
var fn = obj.getThis
fn(); // window
复制代码
词法环境是一种规范类型,基于ECMAScript代码的词法嵌套结构来定义“标识符”和具体函数和变量的关系。存储let,const 定义的函数声明和变量绑定bash
一个词法环境由一个环境记录器和一个(可能存在的)对外部词法环境的引用组成。函数
变量环境其实也是一个词法环境,用来存储变量声明语句在执行上下文中建立的绑定关系,即,存储var声明的变量的绑定ui
在建立阶段,let、const定义的变量变量没有关联任何值,可是var声明的变量会被设置为undefined,因此var变量在声明以前访问值为undefined,但不会报错,即变量声明提高。let、const变量声明前访问会致使引用错误。this
执行阶段完成对全部变量的分配,并执行代码。spa
javascript引擎建立执行上下文栈管理执行代码是建立的全部执行上下文。
当JavaScript脚本第一次执行代码时,会建立一个全局执行上下文,并压入执行栈;以后每次调用函数时,会为该函数建立一个函数执行上下文并压入栈,当函数执行结束,对应当执行上下文从栈中弹出。
下面两段代码的执行结果同样"local",可是执行上下文栈的变化不一样。
var scope = "global";
function checkScope(){
var scope = "local";
function fn(){
return scope;
}
return fn();
}
checkScope();
// 方法执行时 执行上下文栈的变化以下
ESCStack.push(<checkScope> function-Context)
ESCStack.push(<fn> function-Context)
ESCStack.pop()
ESCStack.pop()
复制代码
var scope = "global";
function checkScope(){
var scope = "local";
function fn(){
return scope;
}
return fn;
}
checkScope()();
// 方法执行时 执行上下文栈的变化以下
ESCStack.push(<checkScope> function-Context)
ESCStack.pop()
ESCStack.push(<fn> function-Context)
ESCStack.pop()
复制代码
JavaScript函数执行时用到做用域链,做用域链是在函数定义时建立的。
- 变量对象 Variable Object
- 做用域链 Scope Chain
- this
变量对象是与执行上下文相关的数据做用域,存储在上下文中定义的变量和函数声明。
全局执行上下文中的变量对象就是全局对象,在浏览器中全局对象就是window对象。
在函数执行上下文中,用**活动对象(Activation-Object)**表示比变量对象。互动对象在进入函数执行上下文时被建立,它经过函数的arguments属性初始化。
变量对象包括函数的全部形参、函数声明(function)、变量声明(var)。若是变量名称和已经声明的形参或函数名称相同,变量声明不会干扰已经存在的这类属性。
做用域链保证对执行上下文有权访问的全部变量和函数的有序访问。
做用域的前端,始终是当前执行代码所在执行环境的变量对象;做用域的最后一个对象,始终是全局执行上下文的变量对象。
标识符解析是从做用域链的前端开始,逐层向上搜索标识符的过程。