JavaScript是世界上最受欢迎和最令人讨厌的语言之一。人们爱它是因为它有效力。只需要学习JavaScript而不学习其他任何东西,就可以创建一个完整的堆栈应用程序。它令人讨厌的另一个原因是,它的行为出乎意料,令人心烦意乱,如果您不了解这种语言,可能会让您讨厌它💔。
本问将通过动画的方式解释JavaScript如何在浏览器中执行代码😆。读完本文,你离成为Rockstar开发者又近了一步🎸😎!
执行上下文
“JavaScript中的一切都发生在执行上下文中。”
我希望每个人都记住这句话,因为它很重要。你可以假设这个执行上下文是一个大容器,当浏览器想要运行一些JavaScript代码时调用它。
在这个容器中,有两个组件:内存组件和代码组件。
内存组件也称为可变环境。在这个内存组件中,变量和函数以键值对的形式存储。
代码组件是容器中一次执行一行代码的地方。这个代码组件还有一个有趣的名字,即**“执行线程”**。听起来很酷!
JavaScript是一种同步的单线程语言。这是因为它一次只能按照特定的顺序执行一个命令。
代码的执行
让我们来看一个例子:
var a = 2; var b = 4; var sum = a + b; console.log(sum);
在这个简单的示例中,我们初始化了两个变量a
和b
,并分别赋值了2
和4
。
然后我们将a
和b
的值相加并将其存储在sum
变量中。
让我们看看JavaScript如何在浏览器🤖中执行代码:
浏览器使用两个组件创建一个全局执行上下文,即内存和代码组件。
浏览器将分两个阶段执行JavaScript代码:
- 内存创建阶段
- 代码执行阶段
在内存创建阶段,JavaScript将扫描所有代码,并为代码中的所有变量和函数分配内存。对于变量,JavaScript将在内存创建阶段未定义存储,对于函数,它将保留整个函数代码,我们将在下面的例子中看到。
现在,在第二阶段,也就是代码执行阶段,它开始逐行遍历整个代码。
当它遇到var a = 2
时,它在内存中将2
赋值给'a'
。直到现在,'a'
的值还没有定义。
同样的,它对b
也有同样的作用。它把4
赋值给b
。然后它计算和存储在内存中的值是6
。现在,在最后一步中,它在控制台中打印求和值,然后在代码完成时销毁全局执行上下文。
函数如何在执行上下文中被调用?
与其他编程语言相比,JavaScript中的函数的工作方式是不同的。
举个简单的例子,
var n = 2; function square(num) { var ans = num * num; return ans; } var square2 = square(n); var square4 = square(4);
上面的例子有一个函数,它接受一个number
类型的参数,并返回该数字的平方。
JavaScript将创建一个全局执行上下文,并在我们运行代码的第一阶段为所有变量和函数分配内存,如下所示。
对于函数,它会将整个函数存储在内存中。
下面是令人兴奋的部分,当JavaScript运行函数时,它将在全局执行上下文中创建一个执行上下文。
当它遇到var a = 2
时,它在内存中将2
赋值给'n'
。第2行是一个函数,由于该函数在内存执行阶段已经分配了内存,所以直接跳转到第6行。
Square2
变量将调用square
函数,javascript将创建一个新的执行上下文。
这个square
函数的新执行上下文将在内存创建阶段为函数中出现的所有变量分配内存。
在为函数内的所有变量分配内存之后,它将逐行执行代码。它将获取num
的值,num
的值等于第一个变量的2
,然后它将计算ans
。ans
计算完毕后,它将返回赋给square2
的值。
一旦函数返回值,它将在完成工作后销毁其执行上下文。
现在它将对第7行
或square4
变量执行类似的过程,如下所示。
一旦所有代码执行完毕,全局执行上下文也将被销毁,这就是JavaScript在幕后执行代码的方式。
调用栈
当在JavaScript中调用函数时,JavaScript会创建一个执行上下文。当我们在函数内嵌套函数时,执行上下文将变得复杂。
JavaScript通过调用栈管理代码执行上下文的创建和删除。
一个堆栈(有时被称为“下推堆栈”)是一个有序的项目集合,添加新项目和删除现有项目总是发生在同一末端。
调用堆栈是一种机制,用于跟踪它在调用多个函数的脚本中的位置。
举个例子
function a() { function insideA() { return true; } insideA(); } a();
我们正在创建一个函数'a'
,它调用另一个返回true
的函数'insideA'
。我知道这段代码很蠢,没有做任何事情,但它将帮助我们理解JavaScript如何处理回调函数。
JavaScript将创建一个全局执行上下文。全局执行上下文将分配内存给函数'a'
,并在代码执行阶段调用’函数a’。
为函数a
创建了一个执行上下文,它位于调用堆栈中的全局执行上下文之上。
函数a将分配内存并调用函数inside
。为函数insideA
创建了一个执行上下文,并放置在'function a'
的调用堆栈之上。
现在,这个insideA
函数将返回true
,并将从调用堆栈中移除。
由于'function a'
内部没有代码,执行上下文将从调用堆栈中移除。
最后,全局执行上下文也从调用堆栈中删除。
我希望这篇文章能让你有所收获。💪🏾如果你有任何问题,请随时联系我。