javascript的执行环境、词法环境、变量环境

关于本文内容均基于es5标准

执行环境

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。

执行环境分为:
1)全局执行环境,最外层执行环境,在所有代码未开始执行前就已经创建完毕,页面关闭后销毁。
2) 函数执行环境。函数被调用时创建,函数执行完毕后销毁。
3) Eval函数执行环境。

在第五版中,间接调用 eval 函数会将全局对象作为执行代码的变量环境和词法环境。

“直接”调用是指函数调用涉及eval标识符,而其他方式都算作间接调用。


javascript的执行环境、词法环境、变量环境_第1张图片
chrome控制台内运行示例

一个执行环境包括三个组件:this绑定、词法环境组件、变量环境组件。


javascript的执行环境、词法环境、变量环境_第2张图片
ECMAScript5.1文档截图
词法环境对象

每个词法环境对象包含两部分:

  • 环境记录器
  • 外部环境的引用(可能为空,比如全局词法环境)

环境记录器
环境记录器分为两种:
1)声明式环境记录器
存在于函数作用域中,存储变量、函数、参数。
2)对象式环境记录器
存在于全局作用域和块级作用域中,存储变量、函数。

外部环境引用
如果在当前环境内找不到变量,引擎可以通过引用在外部环境继续查找。

变量环境组件与词法环境组件

执行环境的词法环境和变量环境组件始终为 词法环境对象。

区别是:
let、const声明的变量,外部环境引用保存在词法环境组件中。
var和function声明的变量和保存在环境变量组件中。

以下面代码为例:

let a = 1;
const b = 2;
var c = 3;
function test (d, e) {
  var f = 10;
  return f * d * e;
}
c = test(a, b);

解析阶段的全局环境内的词法环境和变量环境

GlobalLexicalEnvironment = {
  LexicalEnvironment: {
    OuterReference: null,
    EnviromentRecord: {
      Type: 'object',
      a:  ,
      b:  
    },
  },
  VariableEnvironment: {
    EnviromentRecord: {
      type: 'object',
      test: ,
      c: undefined,
    }
  }
}

解析test时的词法环境和变量环境

GlobalLexicalEnvironment = {
  LexicalEnvironment: {
    OuterReference: null,
    EnviromentRecord: {
      Type: 'object',
      a: 1 ,
      b: 2 
    },
  },
  VariableEnvironment: {
    EnviromentRecord: {
      type: 'object',
      c: 3,,
      test: 
    }
  }
}

FunctionLexicalEnvironment = {
  LexicalEnvironment: {
    OuterReference:  ,
    EnviromentRecord: {
      Type: 'Declarative',
      arguments: {0: 1, 1: 2, length: 2}
    },
  },
  VariableEnvironment: {
    EnviromentRecord: {
      Type: 'Declarative',
      f: undefined,
    }
  }
}

执行完毕后的词法环境和变量环境

GlobalLexicalEnvironment = {
  LexicalEnvironment: {
    OuterReference: null,
    EnviromentRecord: {
      Type: 'object',
      a: 1 ,
      b: 2 ,
      test: 
    },
  },
  VariableEnvironment: {
    EnviromentRecord: {
      type: 'object',
      c: 20,
    }
  }
}

FunctionLexicalEnvironment = {,
  LexicalEnvironment: {
    OuterReference:  ,
    EnviromentRecord: {
      Type: 'Declarative',
      arguments: {0: 1, 1: 2, length: 2}
    },
  },
  VariableEnvironment: {
    EnviromentRecord: {
      Type: 'Declarative',
      f:10,
    }
  }
}

------------- 分割线 -----------------

作用域

决定了一段代码能够访问到那些数据,这些数据存放在词法环境对象内。

作用域链

当执行一个函数时,引擎会将函数的执行环境推入执行栈并生成作用域链。

作用域链的顶部永远是当前环境的词法环境对象,下一个词法环境对象来自于包含环境,下下个词法环境对象来自于包含环境的包含环境。作用域链的尾部是全局词法环境对象。

作用域链是一个链表的形式。当我们在一个函数内部调用某一个变量时,会从作用域链顶部开始查找。如果在当前执行环境内存在定义则返回,否则会在当前环境的词法环境组件中引用的外部环境引用中查找。然后重复前面的逻辑,直到找到全局词法环境对象(外部引用环境为null)如果仍然未找到会抛出异常。

你可能感兴趣的:(javascript的执行环境、词法环境、变量环境)