本文共 1090 字,读完只需 4 分钟javascript
JavaScript 是函数式编程语言,做用域也是以函数为单位,那么,这些函数代码块是怎么样的顺序进行的呢, JS 的可执行代码又分为 3 种,不一样类型的代码有不同的执行环境。本文就梳理有关 JS 执行上下文(execution context),也叫执行环境的知识。java
活动的执行代码的上下文在语言底层逻辑上构成一个执行上下文栈(excution context stack),咱们知道,栈有两个行为,压入栈和弹出栈,而且有后进先出
的特色, 最早进入的项会在栈底最后弹出。git
不一样执行环境的有其相应的变量对象(Variable Object),某个执行环境的全部可执行代码都执行完毕后,该环境中的变量对象和函数定义会被清除。github
函数代码会在执行完后清除变量占用的内存,全局代码则会在关闭环境,好比关闭浏览器后清除。web
JS 中可执行的代码可分为三种类型:编程
全局代码浏览器
在 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 的词法做用域的行为,会形成变量环境和执行上下文的混乱,尽可能别使用它。
前面其实已经提到不少关于执行上下文栈的内容,简而言之,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)和做用域链的具体内容,敬请期待吧。
博客内容源自我的公众号,专一分享原创文章,欢迎关注。