JS复习-执行上下文/作用域链/闭包

71 阅读3分钟

JS中的执行上下文和执行栈

什么是执行上下文?

执行上下文是评估和执行JS代码的环境的抽象的抽象概念,JS代码在运行时就是在执行上下文中运行

执行上下文是JS代码运行的环境

执行上下文的种类

  • 全局(默认)执行上下文:创建全局对象windowthis指向全局对象。只有一个
  • 函数执行上下文: 每当函数被调用时,就会为函数创建一个专属的上下文。可以存在多个

执行栈

执行栈被用来存储代码运行时的创建的执行上下文。

JS引擎在遇到代码时,会首先创建一个全局的执行上下文,并压入到栈中。在函数调用时,JS引擎再创建一个函数执行上下文压入栈中。

JS引擎会执行位于栈顶的函数,运行结束后,执行栈弹出已运行函数的执行上下文 。随后引擎再执行下个变成栈顶的函数

代码演示

let a = 'Hello World!';

function first() {
  console.log('Inside first function');
  second();
  console.log('Again inside first function');
}

function second() {
  console.log('Inside second function');
}

first();
console.log('Inside Global Execution Context');

image.png

创建执行上下文

创建执行环境

  1. this的绑定
  2. 词法环境的初始化
  3. 变量环境的初始化

词法环境伪代码


GlobalExectionContext = {   //全局执行上下文
  LexicalEnvironment: {     // 词法环境
    EnvironmentRecord: {    // 词法环境的组件 对象环境记录器  
      Type: "Object",
      // 在这里绑定标识符
    }
    outer: <null>           // 词法环境的组件 外部引用
  }
}

FunctionExectionContext = {  // 函数执行上下文
  LexicalEnvironment: {      // 词法环境
    EnvironmentRecord: {     // 词法环境的组件 声明环境记录器  
      Type: "Declarative",
      // 在这里绑定标识符
    }
    outer: <Global or outer function environment reference> // 词法环境的组件 外部引用
  }
}


变量环境:



let a = 20;
const b = 30;
var c;

function multiply(e, f) {
 var g = 20;
 return e * f * g;
}

c = multiply(20, 30);


GlobalExectionContext = {

  ThisBinding: <Global Object>,

  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 在这里绑定标识符
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    outer: <null>
  },

  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 在这里绑定标识符
      c: undefined,
    }
    outer: <null>
  }
}

FunctionExectionContext = {
  ThisBinding: <Global Object>,

  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 在这里绑定标识符
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>
  },

VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 在这里绑定标识符
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>
  }
}

作用域链

《JavaScript深入之变量对象》中讲到,当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。

闭包

函数能访问到函数外部的变量,则函数和这个变量形成了一个闭包

function foo(){
  var local = 1
  function bar(){
    local++
    return local
  }
  return bar
}

var func = foo()
func()

foo 就是变量local和函数的bar的闭包

闭包目的

隐藏那个能被函数访问到的变量,换句话说,除了能和那个变量形成闭包的函数,其他的方法都不可以访问它。

理解 JavaScript 中的执行上下文和执行栈 JavaScript深入之作用域链