美文网首页
作用域(scope)和执行环境(context)

作用域(scope)和执行环境(context)

作者: yyyzhen | 来源:发表于2017-09-30 16:57 被阅读0次

JavaScript的scope和context都是不能被我们直接使用的东西,存在于JavaScript的整个执行过程,分为代码编译阶段和代码执行阶段,在代码编译阶段,编译器将代码翻译成可执行代码,此时会确定函数的作用域和作用域链;在代码的执行阶段,引擎执行代码时会创建代码的执行环境。所以首先我们要明白一点,执行环境和作用域不是同一个东西

作用域

作用域是负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前的执行的代码对这些标识符的访问权限。——《你不知道的JavaScript(上卷)》

JavaScript中作用域可以分为全局作用域和局部作用域。
全局作用域是整个程序在运行时都能访问的;局部作用域中包含了函数作用域和块级作用域。

下图展示了函数作用域和全局作用域之间的关系:


作用域图示(截取自《你不知道的JavaScript(上卷)》)

块级作用域在ES3中有with和catch两个,在ES6中引入了let和const

    /* with */
    var obj = {a: 0}
    with(obj) {
      a = 1
    }
    console.log(obj)  // {a:1}
    console.log(a)  // ReferenceError: a is not define

    /* catch */
    try {
      undefined() // 制造一个错误
    } catch(err) {
      console.log(err) // 输出这个err
    }
    console.log(err) // ReferenceError: err is not define

利用catch的块作用域,我们可以在不兼容ES6的环境下使用let的兼容写法,可以看下面这个例子:

/* 无块级作用域 */
var i = 0;
for(i; i < 10; i++) {
  var j = i
  setTimeout(function(){
    console.log(j)  // 输出10个10
  })
}
/* 使用let */
var i = 0
for(i; i < 10; i++) {
  let j = i
  setTimeout(function(){
    console.log(j)  // 输出从0到9 10个数字
  })
}

/* 使用catch */
var i = 0;
for (i; i < 10; i++) {
  try {
    throw undefined  // 产生错误,值为undefined
  } catch (j) {
    j = i
    setTimeout(function () {
      console.log(j)  // 输出从0到9 10个数字
    })
  }
}

词法作用域
JavaScript是用的词法作用域,所以作用域和作用域链是在代码编译阶段就确定的东西,下面看一个简单的例子:

var a = 2;
function fn1() {
  console.log(a);
}
function fn2() {
  var a = 3;
  fn1();
}
fn2();  // 2

在上面的代码中,变量a、fn1和fn2是在全局作用域中声明的,fn1和fn2也产生了各自的函数作用域,但因为作用域和作用域链是在函数定义阶段就确定的,所以在执行阶段,fn1()输出的a就是全局变量中的a。

执行环境

每个函数都有自己的执行环境(execution context)。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。——《JavaScript高级程序设计》

console.log('global');
function func1() {
  console.log('func1');
  var func2 = function() {
    console.log('func2');
  }
  func2();
}
func1();
  1. 浏览器开始运行,环境栈中添加global执行环境,输出global
  2. 执行了func1(),环境栈中添加func1执行环境,输出func1
  3. 在func1中执行了func2(),环境栈中添加func2执行环境,输出func2
  4. func2执行完毕,环境栈中推出func2执行环境
  5. func1执行完毕,环境栈中推出func1执行环境

上面这个例子的环境栈变化如下图所示:

上例图解

执行环境和作用域的区别

自我理解(未确认):JavaScript的代码在执行前会确定作用域,产生作用域链,然后当执行到某个函数的时候,函数执行环境就被推入环境栈,执行环境上就会添加变量对象、活动对象、作用域链这些东西。变量对象和活动对象是差不多的,只是状态不一样,一个是执行前确定的,一个是执行时用到的,上面保存了函数中定义的变量或者函数声明。作用域是一套规则,用来确定在何处以及如何查找对象,当作用域嵌套的时候,就产生了作用域链,当前作用域没有找到变量的时候,就在上一层作用域查找,直到找到变量或者到达最外层作用域。

相关文章

  • 作用域(scope)和执行环境(context)

    JavaScript的scope和context都是不能被我们直接使用的东西,存在于JavaScript的整个执行...

  • 深入JavaScript之Scope(作用域)以及Context

    Scope和Context: 咱俩不是一个东西 我是Scope(作用域),那是隔壁邻居Context(执行上下文)...

  • Javascript 运行上下文和作用域链

    一、作用域Scope和上下文Context 在javascript中,作用域scope和上下文context是两个...

  • js面试题

    一道腾讯js面试题 题目如下: 对作用域链(scope chain)、执行环境(execution context...

  • 作用域和作用域链

    1、什么是作用域execution context? 作用域又叫执行环境,或者执行上下文,执行环境定义了变量或者函...

  • js的执行环境和作用域

    执行环境和作用域 1、执行环境(execution context) 执行环境定义了变量或函数有权访问的其他数据,...

  • 梳理 this 关键字的指向

    一、this 指向梳理图 二、逐个学习 先说明上下文(context)和作用域(scope)的区别: 作用域(sc...

  • JS作用域链

    当代码在一个环境中执行的时候,会创建变量对象的作用域链(scope chain)作用域链的用途是:保证对执行环境...

  • 第四章 变量,作用域和内存问题(二)

    2. 执行环境及作用域   执行环境(execution context,为简单起见,有时也称为“环境”)是Jav...

  • 浅谈js作用域

    当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境...

网友评论

      本文标题:作用域(scope)和执行环境(context)

      本文链接:https://www.haomeiwen.com/subject/zyxkjxtx.html