返回
揭秘 JavaScript 执行机制:从执行上下文到执行栈
前端
2023-12-01 08:24:00
站在技术博客创作专家的角度,JavaScript 作为一门高级的编程语言,其执行机制并不是简单明了,但我们却可以从执行上下文和执行栈两个概念出发,揭开 JavaScript 执行背后的神秘面纱。
理解执行上下文
在 JavaScript 中,执行上下文是一个抽象的概念,它代表了 JavaScript 代码执行的环境,而当前 JavaScript 代码正在运行的环境就是当前的执行上下文,一般可以简单地理解为一个全局执行上下文或一个函数执行上下文。
- 全局执行上下文 :当 JavaScript 代码开始执行时,首先创建全局执行上下文,它负责处理全局变量和全局函数,并且是所有其他执行上下文(函数执行上下文)的父级。
- 函数执行上下文 :当一个函数被调用时,会创建一个新的函数执行上下文,这个新创建的函数执行上下文会包含函数的参数、局部变量和函数内部的代码,同时也是全局执行上下文的子级,与全局执行上下文形成层级结构。
理解执行栈
执行栈是一个数据结构,它存储着所有被调用的函数执行上下文,当一个函数被调用时,它的执行上下文会被压入执行栈中,当函数执行完毕后,它的执行上下文会被从执行栈中弹出。
执行栈的工作方式:
- JavaScript 引擎首先创建一个全局执行上下文,并将它压入执行栈中。
- 当一个函数被调用时,一个新的执行上下文被创建并压入执行栈中,该执行上下文包含函数的参数、局部变量和函数内部的代码。
- JavaScript 引擎开始执行函数内部的代码。
- 当函数执行完毕后,它的执行上下文被从执行栈中弹出,控制权返回给调用它的函数。
- 如果调用它的函数也执行完毕,那么它的执行上下文也会被从执行栈中弹出,控制权返回给父级执行上下文。
- 当所有函数执行完毕后,全局执行上下文也被从执行栈中弹出,JavaScript 代码执行结束。
执行上下文和执行栈的关系:
- 执行栈是一个先进后出的数据结构,每次函数被调用时,它的执行上下文都会被压入执行栈中,而当函数执行完毕后,它的执行上下文会被从执行栈中弹出。
- 执行上下文和执行栈是 JavaScript 执行机制的核心组成部分,两者之间有着密切的关系,可以帮助理解变量提升、作用域、闭包等概念。
变量提升:
- 在 JavaScript 中,变量提升是一个有趣且容易让人混淆的概念。
- 当 JavaScript 引擎遇到一个变量声明时,它会将该变量提升到当前执行上下文的顶部,无论该变量是在代码的开头还是后面声明。
- 例如:
function myFunction() {
var a = 10;
console.log(a); // 输出:10
var b = 20;
console.log(b); // 输出:20
}
myFunction();
- 在这个例子中,变量
a
和b
都在函数myFunction()
的开头声明,但是a
被提升到函数执行上下文的顶部,因此当我们使用console.log()
输出a
的值时,它会输出10
。
作用域:
- 作用域是 JavaScript 中另一个重要的概念。
- 作用域决定了变量的可访问性,它定义了变量可以在哪些地方被访问。
- JavaScript 中有两种作用域:全局作用域和局部作用域。
- 全局变量在全局执行上下文中声明,可以在任何地方访问。
- 局部变量在函数执行上下文中声明,只能在该函数内部访问。
- 例如:
var globalVariable = 10;
function myFunction() {
var localVariable = 20;
console.log(globalVariable); // 输出:10
console.log(localVariable); // 输出:20
}
myFunction();
console.log(globalVariable); // 输出:10
console.log(localVariable); // 输出:错误:localVariable 在全局执行上下文中不可用
- 在这个例子中,
globalVariable
是一个全局变量,它可以在任何地方访问。localVariable
是一个局部变量,只能在函数myFunction()
内部访问。当我们试图在全局执行上下文中访问localVariable
时,我们会得到一个错误,因为localVariable
在全局执行上下文中不可用。
闭包:
- 闭包是 JavaScript 中一个高级的概念,它允许函数访问其父级函数的作用域,即使父级函数已经执行完毕。
- 闭包可以被用来实现私有变量和私有方法。
- 例如:
function createCounter() {
var counter = 0;
return function() {
counter++;
return counter;
};
}
var myCounter = createCounter();
console.log(myCounter()); // 输出:1
console.log(myCounter()); // 输出:2
console.log(myCounter()); // 输出:3
- 在这个例子中,
createCounter()
函数返回一个新的函数,该函数可以访问其父级函数createCounter()
的作用域,即使createCounter()
函数已经执行完毕。 - 这使得我们可以使用闭包来实现私有变量和私有方法。
希望这篇博文能帮助你理解 JavaScript 中的执行上下文和执行栈,掌握这些概念将使你成为一个更加优秀的 JavaScript 开发者。