- 作者:老汪软件技巧
- 发表时间:2024-11-22 10:04
- 浏览量:
前言
JavaScript 是一种广泛使用的高级编程语言。它以其灵活的语法和强大的功能著称,同时也拥有复杂的底层运行机制。本文将深入探讨 JavaScript 的底层运行逻辑,帮助读者全面理解 JavaScript 的工作原理
JavaScript弱类型
JavaScript是一种弱类型语言(也叫动态类型或松散类型),它不像java和c++是静态类型,需要在编译阶段对代码类型进行严格检查。像java执行过程中.java(代码文件) -> javac compile .o 二进制文件 -> 运行有独立的编译阶段。而因为JavaScript和python是脚本语言,不需要单独编译。没有独立的编译过程,编译和执行是紧密相连的,只是在运行之前有个短暂的编译过程。这可能会导致一些问题。如下面的代码:
console.log(name); // undefined 变量提升
var name ="大飞"
此时代码会输出 undefined
这是因为变量提升(不懂可以看:面试官(4):请你讲讲你对“提升”的理解),在引擎眼中看到的代码可能是这样
var name;
console.log(name);
name="大飞"
变量在声明时被初始化为undefined,给变量分配了别人不可占有的内存。此时的变量提升只提升了变量却不会提升赋值。
不仅变量会提升,函数也会提升
console.log(fun)
function fun(){
}
这几行代码的输出结果是函数名
变量提升实际上是在预编译阶段发生的。JavaScript引擎在预编译阶段会扫描整个代码块,识别所有的变量声明和函数声明,并将它们提升到当前作用域的顶部。我们在前文也提到了JS它是在执行之前会进行短暂的编译。接下来,我们将详细探讨执行上下文,以便更好地理解JavaScript的执行机制。
执行上下文和调用栈执行上下文
什么是执行上下文呢,简单来说,他是执行JavaScript代码的环境的抽象概念,代码都是在执行上下文中来运行的。
执行上下文的类型
一般来说分为两个类型:
调用栈
调用栈也被称为执行栈,是一种拥有 LIFO(后进先出)数据结构的栈,被用来存储代码运行时创建的所有执行上下文。当引擎运行时,会创造一个全局执行上下文并压入调用栈。每遇到一个函数时,会创建一个函数执行上下文并压入栈的顶部。引擎会执行在调用栈顶部的函数,执行结束后,从栈内弹出。
让我们根据一段来代码来理解:
let a = 'Hello World!';
function sayhi() {
console.log('hello');
saybye();
console.log('hi');
}
function saybye() {
console.log('byebye');
}
sayhi();
console.log('good bye');
上述代码在运行时,JavaScript引擎创建了一个全局执行上下文,并把它压入调用栈内。遇到sayhi()调用后,创建一个新的函数执行上下文并压到调用栈顶部。
当在sayhi()函数内部调用saybye()时,又创建一个新的函数执行上下文并压入调用栈顶部。此时当执行完saybye()后,saybye()从调用栈弹出。此时才到sayhi()执行上下文。所以此时代码执行结果是:
创建执行上下文
由上可知JavaScript如何管理执行上下文,现在我们来分析如何创建执行上下文。
创建执行上下文分为两个阶段:创建阶段和执行阶段
创建阶段会:创建变量环境组件和创建词法环境组件
变量环境
简单来说,变量环境是指在程序执行过程中,存储变量(只用var)及其值的集合,它定义了变量的作用域和生命周期。
词法环境
词法环境是程序中静态定义的一个概念,它决定了变量和函数在代码中的可见性和作用域。储存(let const)关键字声明的变量。
分为全局环境,函数环境,块级环境。
作用域链就是由一系列词法环境组成的链表。
执行阶段
JavaScript的执行可以说是十分不容易
js 代码要执行
注意— 在执行阶段,如果 JavaScript 引擎不能在源码中声明的实际位置找到let变量的值,它会被赋值为undefined。
结语
经过了这篇文章对JavaScript运行的深度解读。掌握了会让你更轻松的理解其他概念,类似于闭包,作用域。