个人理解:
执行环境的概念:每个函数在调用的时候会创建一个自己的执行环境。当执行流进入一个函数的时候,函数的环境就会被推入一个环境栈,而在函数执行之后,栈将其执行环境弹出,并将控制权移交给之前的执行环境。执行环境定义了变量和函数有权访问的其他数据,并定义了他们各自的行为;
变量对象:当函数被调用的时候,每个执行环境都会有一个与之相关的变量对象,环境中定义的所有变量和对象都保存在这个对象。
变量对象(variable object) 是与执行上下文相关的 数据作用域(scope of data) 。 它是与上下文关联的特殊对象,用于存储被定义在上下文中的 变量(variables) 和 函数声明(function declarations) 。 它是一个抽象的概念,不同的上下文中,它表示使用不同的object。例如,在global全局上下文中,变量对象也是全局对象自身[global object]。(这就是我们可以通过全局对象的属性来指向全局变量)。
作用域链:在一个函数被创建的时候,会创建一个预先包含全局变量对象的作用域链,并把这个作用域链保存于内部的【Scope】属性中;所以说创建任何一个函数的时候就会创建包含全局变量对象的作用域链;
当函数第一次被调用的时候,会创建一个执行环境以及相应的作用域链,然后通过复制函数的【scope】属性中的对象构建起执行环境的作用域链,然后又有一个活动对象(这里作为变量对象)被创建并被推入执行环境作用域链的前端,最后使用this,arguments,和其他命名参数来初始化函数活动对象(如果是函数,则将其活动对象作为变量对象);
性质:1,作用域链的前端始终都是当前执行代码所在环境的变量对象
2,全局执行环境的的变量对象之中都是作用域链的最后一个变量对象;
3,作用域链的作用在于保证对执行环境中有权访问的所有变量和函数的顺序访问;
4,内部环境变量可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境的任何变量和函数;
5,作用域链本质是一个指向变量对象的指针列表,他只引用但不实际包含变量对象。
度娘精选:
执行上下文栈:注意,一个function可能产生无限的上下文环境,因为一个函数的调用(甚至递归)都产生了一个新的上下文环境。
一系列活动的执行上下文从逻辑上形成一个栈。栈底总是全局上下文,栈顶是当前(活动的)执行上下文。当在不同的执行上下文间切换(退出的而进入新的执行上下文)的时候,栈会被修改(通过压栈或者退栈的形式)。
当javascript代码文件被浏览器载入后,默认最先进入的是一个全局的执行上下文。当在全局上下文中调用执行一个函数时,程序流就进入该被调用函数内,此时引擎就会为该函数创建一个新的执行上下文,并且将其压入到执行上下文堆栈的顶部。浏览器总是执行当前在堆栈顶部的上下文,一旦执行完毕,该上下文就会从堆栈顶部被弹出,然后,进入其下的上下文执行代码。这样,堆栈中的上下文就会被依次执行并且弹出堆栈,直到回到全局的上下文。
执行上下文:也称为执行环节,一个执行的上下文可以抽象的理解为object。每一个执行的上下文都有一系列的属性(我们称为上下文状态),他们用来追踪关联代码的执行进度。主要有三个属性:变量对象(variable object),this指针(this value),作用域链(scope chain)。
活动对象
当函数被调用者激活,这个特殊的活动对象(activation object) 就被创建了。它包含普通参数(formal parameters) 与特殊参数(arguments)对象(具有索引属性的参数映射表)。活动对象在函数上下文中作为变量对象使用。
即:函数的变量对象保持不变,但除去存储变量与函数声明之外,还包含以及特殊对象arguments 。
作用域链优化: 从作用域链的结构可以看出,在运行期上下文的作用域链中,标识符所在的位置越深,读写速度就会越慢。因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。一个好的经验法则是:如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。