JS回归基础之执行上下文/作用域链

最近在研究 JavaScript 基础性的东西,但是看到对于执行上下文的解释我发现有两种,一种是执行上下文包含:variable object(变量对象)scope(作用域)this value(this 值),另外一个种是包含:lexical environment(词法环境)variable environment(变量环境)this value(this 值)

后面我查阅了不少博客以及 ES3 和 ES5 的规范才了解到,第一种是 ES3 的规范,经典书籍《JavaScript 高级程序设计》第三版就是这样解释的,也是网上广为流传的一种,另一种是 ES5 的规范。

什么是执行上下文?

简而言之,执行上下文是评估和执行 JavaScript 代码的环境的抽象概念。每当 Javascript 代码在运行的时候,它都是在执行上下文中运行。

执行上下文的类型

1. 全局执行上下文

任何不在函数内部的代码,它会执行两件事:创建一个全局的 window 对象(浏览器的情况下),并且设置 this 的值等于这个全局对象。一个程序中只会有一个全局执行上下文。

2. 函数执行上下文

函数被调用时创建的,函数上下文可以有任意多个

3. Eval 函数执行上下文

不常用,所以不做介绍

执行上下文

每个执行环境/执行上下文,可以抽象的理解为一个object,它由以下几个属性构成

executionContext:{
    
    
    variable object:vars,functions,arguments,  //变量对象(简称VO)
    scope chain: variable object + all parents scopes, //作用域链
    thisValue: context object //this值
}

在这里插入图片描述
this的指向,实在函数被调用的时候确定的也就是执行上下文被创建时确定的。
在函数执行过程中,this一旦被确定,就不可更改了。

变量对象(variable object)

每一个执行上下文都会分配一个变量对象(variable object),变量对象的属性由 变量(variable)函数声明(function declaration) 构成。
在函数上下文情况下,参数列表(parameter list)也会被加入到变量对象(variable object)中作为属性。变量对象与当前作用域息息相关。
不同作用域的变量对象互不相同,它保存了当前作用域的所有函数和变量。

这里有一点特殊就是只有 函数声明(function declaration) 会被加入到变量对象中,而 函数表达式(function expression)则不会。看代码:

// 函数声明
function a(){
    
    }
console.log(typeof a); // "function"

// 函数表达式
var b = function _b(){
    
    };
console.log(typeof b); // "function"
console.log(typeof _b); // "undefined"

活动对象(activation object)

当函数被激活,那么一个活动对象(activation object)就会被创建并且分配给执行上下文。活动对象由特殊对象 arguments 初始化而成。随后,他被当做变量对象(variable object)用于变量初始化。

function a(name, age){
    
    
    var gender = "male";
    function b(){
    
    }
}
a(“k”,10);

a被调用时,在a的执行上下文会创建一个活动对象AO,并且被初始化为 AO = [arguments]。随后AO又被当做变量对象(variable object)VO进行变量初始化,此时 VO = [arguments].concat([name,age,gender,b])。

作用域

JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。函数的作用域在函数定义的时候就决定了。

作用域链(scope chain)

每个执行环境的作用域链由当前环境的变量对象及父级环境的作用域链构成。
函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,你可以理解 [[scope]] 就是所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!

词法环境

词法环境是一种持有标识符—变量映射的结构。(这里的标识符指的是变量/函数的名字,而变量是对实际对象[包含函数类型对象]或原始数据的引用)

词法环境有两种类型:

  1. 全局环境
    (在全局执行上下文中)是没有外部环境引用的词法环境。全局环境的外部环境引用是 null。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 window 对象)还有任何用户定义的全局变量,并且 this的值指向全局对象。
  2. 函数环境
    函数内部用户定义的变量存储在环境记录器中。并且引用的外部环境可能是全局环境,或者任何包含此内部函数的外部函数。

词法环境的内部有两个组件:

  1. 环境记录器:是存储变量和函数声明的实际位置
    环境记录器也有两种类型
    1.声明式环境记录器: 存储变量、函数和参数。
    2.对象环境记录器:用来定义出现在全局上下文中的变量和函数的关系。
    简而言之,
    全局环境中,环境记录器是对象环境记录器。
    函数环境中,环境记录器是声明式环境记录器。

注意 — 对于函数环境,声明式环境记录器还包含了一个传递给函数的 arguments
对象(此对象存储索引和参数的映射)和传递给函数的参数的 length

  1. 外部环境的引用:意味着它可以访问其父级词法环境(作用域)。

变量环境

它同样是一个词法环境,其环境记录器持有变量声明语句在执行上下文中创建的绑定关系。
如上所述,变量环境也是一个词法环境,所以它有着上面定义的词法环境的所有属性。
在 ES6 中,词法环境组件和变量环境的一个不同就是前者被用来存储函数声明和变量(let 和 const)绑定,而后者只用来存储 var 变量绑定。

this

JS回归基础之this

参考:
https://juejin.cn/post/6844903682283143181
https://mp.weixin.qq.com/s/4sUErmlxourruYpOxsSlZA

猜你喜欢

转载自blog.csdn.net/qq_42816550/article/details/111460572