JS中执行上下文的理解

目录

引入问题

执行上下文是什么

执行上下文的分类

生命周期

执行栈


引入问题

JS代码执行顺序有时与代码先后顺序有所差异,与预期是有差别的,例如下面的例子函数声明和函数表达式两者执行就不相同

//函数声明
function f1() {
    console.log('我是f1+1');
};
f1(); //我是f1+2

function f1() {
    console.log('我是f1+2');
};
f1(); //我是f1+2


//函数表达式
var f1 = function () {
    console.log('我是f1+1');
};
f1(); //我是f1+1

var f1 = function() {
    console.log('我是f1+2');
};
f1(); //我是f1+2

注:

  • 函数声明和函数表达式的区别
    • 函数声明
      • JS中有变量被提升的机制,即变量函数声明会被提升到作用域最前面
      • 当是函数声明时,函数调用可在函数声明的父级作用域中函数生命前调用,可以正常调用函数
    • 函数表达式
      • 函数表达式无提升
      • 当在表达式前面进行调用时,则不能正常调用

从上例中易知代码执行时发生变化,在代码执行前JS引擎会先创建对应的执行上下文

执行上下文是什么

执行上下文是对JS代码执行环境的抽象概念,即只要有JS代码在运行,则一定是在执行上下文中进行运行。

执行上下文的分类

  • 全局执行上下文:即浏览器中的全局对象是window对象,this指向的是这个全局。即有一个
  • 函数执行上下文:当函数被调用的时候被创建,每次调用函数会创建一个新的执行上下文。即有无数个(这么多的执行上下文是使用栈管理,下文中解释栈的使用)
  • Eval函数执行上下文:是eval函数中的代码,很少使用

注解:

  • 调用函数创建的新的上下文会有一个私有作用域,函数内部声明的任何变量都不能在这个函数作用外进行访问,只能在函数内部进行访问

生命周期

执行上下文的生命周期包括阶段: 创建阶段、执行阶段、回收阶段

创建阶段

  1. 确定this的值(This Binding)
    • 在全局执行上下文时,this总是指向全局对象。
    • 函数执行上下文中,this值取决于函数调用方式,被对象调用则指向对象,否则一般指向全局对象windows或undefined
  2. 语法环境(LexicalEnvironment)组件被创建 -- 两个组成:全局环境(this指的是全局对象)、函数环境
  3. 变量环境(VariableEnvironment)组件被创建

变量提升的主要原因:--创建阶段时var生命的变量赋值undefined值

创建阶段对于var、let、const的赋值状态: let和const定义变量在创建阶段没有被赋值,var生命的变量在从创建阶段被赋值undefined。 -- 原因:在创建阶段,代码处扫描变量和函数声明,然后将函数声明存储在环境中,单变量会被初始化成undefined(var声明时)和保持初始状态(let、const声明时)

执行阶段

  1. 执行变量赋值
  2. 代码执行

注解:当JS引擎源代码中找不到变量的值,将分配undefined值

回收阶段

  1. 执行上下文出栈
  2. 等待虚拟机回收上下文

执行栈

执行栈,也为调用栈,先进后出结构,用于存储代码执行期间创建的所有执行上下文

执行顺序:

  1. JS引擎开始执行第一行脚本代码,先创建一个全局执行上下文之后将它压倒执行栈中。
  2. 每当引擎遇到一个函数时,会创建一个函数执行上下文,然后将这个和执行上下文压到执行栈中。
  3. 引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),该函数执行结束后,对应的执行上下文会被弹出,然后控制流程到达执行栈的下一个执行上下文

注:JS代码执行完毕前在执行栈底部永远有个全局执行上下文

转化成图的形式

JS中执行上下文的理解_第1张图片

流程:

  • 创建全局上下文请压入执行栈
  • first函数被调用,创建函数执行上下文并压入栈
  • 执行first函数过程遇到second函数,再创建一个函数执行上下文并压入栈
  • second函数执行完毕,对应的函数执行上下文被推出执行栈,执行下一个执行上下文first函数
  • first函数执行完毕,对应的函数执行上下文也被推出栈中,然后执行全局上下文
  • 所有代码执行完毕,全局上下文也会被推出栈中,程序结束

你可能感兴趣的:(js,javascript,前端)