JavaScript 之执行上下文

本文共 1090 字,读完只需 4 分钟javascript

概述

JavaScript 是函数式编程语言,做用域也是以函数为单位,那么,这些函数代码块是怎么样的顺序进行的呢, JS 的可执行代码又分为 3 种,不一样类型的代码有不同的执行环境。本文就梳理有关 JS 执行上下文(execution context),也叫执行环境的知识。java

活动的执行代码的上下文在语言底层逻辑上构成一个执行上下文栈(excution context stack),咱们知道,栈有两个行为,压入栈和弹出栈,而且有后进先出的特色, 最早进入的项会在栈底最后弹出。git

不一样执行环境的有其相应的变量对象(Variable Object),某个执行环境的全部可执行代码都执行完毕后,该环境中的变量对象和函数定义会被清除。github

函数代码会在执行完后清除变量占用的内存,全局代码则会在关闭环境,好比关闭浏览器后清除。web

1、代码类型

JS 中可执行的代码可分为三种类型:编程

  1. 全局代码
  2. 函数代码
  3. Eval 代码

全局代码浏览器

在 web 浏览器中,全局执行环境是 window 对象,全部的全局变量和函数都是做为 window 的属性和方法存在。bash

全局代码的执行上下文栈能够表示为:闭包

ECStack = [
    globalContext
]
复制代码

函数代码app

当执行函数代码时,函数代码上下文被压入到执行上下文栈中。函数代码的执行环境中,有本身的内部的定义的变量和声明。

function foo1() {
    var name1 = "a";
    console.log(name1)
}

function foo2(){
    var name2 = "b";
    console.log(name2)
}

foo1();
foo2();
复制代码

上面的执行上下文能够表示为:

ECStack = [
    globalContext
];

ECStack.push(<foo1> functionContext);
ECStack.pop();
ECStack.push(<foo2> functionContext);
ECStack.pop();
复制代码

一个函数,可能有多个执行上下文,每一个函数的调用都会产生新的上下文。

function foo() {
    ...
}

foo("a");
foo("b");
foo("c");
复制代码

eval 代码

eval 关键字接受一个字符串做为参数,并将其做为书写文字上下文的代码。

function foo(str, a) {
    eval( str );  // 声明一个新变量
    console.log(a, b);
}
var b = 123;

foo("var b = 456 ", 123) // 123, 456
复制代码

以上代码引用《你不知道的 JavaScript》的例子,eval 函数中的字符串,被当作可执行代码,最后在 foo 函数中声明了 b 变量,并覆盖了 foo 函数外部的 b 变量。

eval 函数和 JS 的词法做用域的行为,会形成变量环境和执行上下文的混乱,尽可能别使用它。

2、执行上下文栈

前面其实已经提到不少关于执行上下文栈的内容,简而言之,JS 在遇到全局代码,函数代码,eval 代码时,会建立相应的执行上下文,不一样的上下文,有其变量对象(variable object: VO)和做用域。

看这一段代码:

function func3() {
    console.log('fun3')
}

function func2() {
    func3();
}

function func1() {
    func2();
}

func1();
复制代码

以上代码引用自冴羽的github,代码顺序用执行上下文栈来表示就是:

ECStack.push(globalContext);

// 调用 func1(), 进入 func1 执行环境
ECStack.push(<func1> functionContext);

// func1中调用了 func2,进入 func2 的执行上下文
ECStack.push(<func2> functionContext);

// func2 调用 func3, 进入 func3 的执行上下文
ECStack.push(<func3> functionContext);

// func3 执行完毕,退出 func3 执行环境
ECStack.pop();

// func2 执行完毕,退出 func2 执行环境
ECStack.pop();

// func1 执行完毕,退出 func1 执行环境
ECStack.pop();
复制代码

函数代码执行完毕后,执行上下文栈底只剩下全局代码上下文 globalContext, 直到关闭浏览器才会完全清空执行上下文栈。

总结

代码在执行时会建立由不一样做用域构成的做用域链做用域链保证 JS 中的变量和函数都可以有序地访问和执行。

若是是函数代码,则将其 活动对象 做为变量对象,活动对象最开始时只包含一个对象,即 arguments 对象。

后面的文章会介绍变量对象(VO)和做用域链的具体内容,敬请期待吧。

博客内容源自我的公众号,专一分享原创文章,欢迎关注。

掘金专栏 JavaScript 系列文章

  1. JavaScript之变量及做用域
  2. JavaScript之声明提高
  3. JavaScript之执行上下文
  4. JavaScript之变量对象
  5. JavaScript原型与原型链
  6. JavaScript之做用域链
  7. JavaScript之闭包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值传递
  11. JavaScript之例题中完全理解this
  12. JavaScript专题之模拟实现call和apply
相关文章
相关标签/搜索