JS执行上下文的那些事

62 阅读4分钟

最后更新时间:2023-06-02 13-59-20

代码段

// 全局代码
<script type="text/javascript">// 代码段...</script>;

// eval代码接收的也是一段文本形式的代码
eval("alert(123)");

// 函数体是代码是因为函数在创建时,本质上是new Function(...)得来的,其中需要传入一个文本形式的参数作为函数体
function fn(x) {
  console.log(x + 5);
}

执行上下文

在一段 JS 代码执行之前,浏览器会做一些准备工作

  1. 对代码段中的 变量,函数表达式进行声明, 而不是赋值,变量赋值 是在赋值语句执行的时候进行的
  2. 对代码段中的 this 进行赋值
  3. 对代码段中的函数声明 进行赋值

如果代码段是函数体情况

  1. arguments 变量进行赋值
  2. 对自由变量进行赋值,并确定取值作用域

执行上下文环境

在代码执行之前,将要用到的所有变量都事先拿出来,有的直接赋值,有的先用 undefined 占个空

  1. 函数每被调用一次,都会产生一个新的执行上下文环境.(因为不同的调用可能会有不同的参数)
  2. 函数在定义的时候(不是调用的时候),就已经确定了函数体内部自由变量的作用域

执行上下文栈

  1. 执行全局代码时,会产生一个执行上下文环境
  2. 每次调用函数都又会产生执行上下文环境
  3. 当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境
  4. 处于活动状态的执行上下文环境永远只有一个
  5. 其实这是一个压栈出栈的过程--执行上下文栈

作用域

最大的用处就是隔离变量,不同作用域下同名变量不会有冲突

  1. JavaScript 除了全局作用域之外,只有函数可以创建的作用域
  2. 一段代码中,每一个函数都会形成一个作用域
  3. 作用域有上下级的关系,上下级关系的确定就看函数在那个作用域下创建的
  4. 作用域只是一个底盘,一个抽象的概念,其中没有变量,要通过作用域对应的执行上下文环境获取变量的值,同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。
  5. 所有,作用域中变量的值是在执行过程中产生确定的,但是作用域是在函数创建时就确定了。
  6. 所以,如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再到其中寻找变量的值

作用域链

沿着作用域上下级寻找,我们称之为作用域链

自由变量

  1. 在 A 作用域中使用过了变量 X,但是却没有在 A 作用域中声明,对于 A 作用域来说,X 就是一个自由变量
  2. 寻找自由变量的值,要到创建这个函数的作用域取值(是创建),而不是(调用)----这就是所谓的"静态作用域"

this 指向问题

  1. 构造函数中的 this,this 指向构造函数创建出来的对象
  2. 函数作为一个对象的属性,并且作为对象的一个属性被调用时,函数中的 this 指向该对象
  3. 函数用 call 或者 apply 调用时,this 的值就取传入的对象的值。
  4. 全局&调用普通函数 this 指向 window 5.在构造函数的 prototype 中 this,指向当前对象的值

注释:在函数中 this 到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了,因为 this 的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境

总结

  1. 作用域的上下级,在函数创建时候就已经确定了。
  2. this 的指向问题取决于函数执行时候。
  3. 函数中自由变量的取值,需要创建这个函数时的作用域查找。