浏览器中JS的执行机制

280 阅读5分钟

一,V8引擎:JS的解释器和编译器

在上一篇文章中我们了解了为什么计算机能够读懂JS编程语言,因为在JS的客户端中,浏览器里存在着JS引擎,如著名的ChromeV8引擎。那么V8引擎是怎么处理代码执行功能的呢?这就要聊到V8引擎的整体设计,而V8引擎的整体设计可以分为两个主要部分:解释器和编译器。

编译器

编译器是将源代码完全转换为目标代码(如机器码或汇编代码)的工具,通俗来讲就是语言的翻译器,“翻译官”。在“翻译”过程中,编译器会进行词法分析、语法分析、语义分析、优化等多个阶段,最终生成可以直接由计算机执行的目标代码。生成的目标代码通常是二进制形式的,可以直接被计算机的处理器执行。代码在执行前需要进行编译操作,用于确定代码之间的各种关联

解释器

解释器通常会直接解释并执行源代码。但是,有些解释器会包含一个小型的编译器,用于将源代码编译成某种中间表示形式(如字节码),然后再解释执行这个中间表示形式。这种解释器通常被称为即时编译器(JIT Compiler)或即时解释器(JIT Interpreter)。

  • -了解了V8的核心组成部分后我们不难做出总结————V8引擎在处理代码时通常分为三步:词法分析,语法分析和代码生成。

二,词法分析

词法分析是读懂代码的第一步,代码在被执行前必须做词法分析,他是V8解析和执行代码的基础。

用通俗的话来说,词法分析的主要任务是“读”代码,并将代码“拆”成一个个有意义的“零件”。这些“零件”在编程中通常被称为“词法单元”,它们包括变量名、函数名、关键字、操作符、数字常量、字符串常量等。

JS词法分析器会按照预定的规则(由编程语言的语法定义)来读取源代码字符流,并将其分割成一个个的词法单元。 举个例子吧,假设我们有如下的JavaScript代码片段:

var x = 5 + 3;

词法分析器会按照以下方式处理这段代码:

  1. 读取到var,识别出它是一个关键字,并生成一个代表关键字的词法单元。
  2. 读取到空格,通常空格在编程语言中是被忽略的(除非在特定的上下文中,如字符串内部),所以词法分析器会跳过它。
  3. 读取到x,识别出它是一个标识符(在这个例子中是一个变量名),并生成一个代表标识符的词法单元。
  4. 读取到=,识别出它是一个赋值操作符,并生成一个代表操作符的词法单元。
  5. 读取到数字5,识别出它是一个数字常量,并生成一个代表数字常量的词法单元。
  6. 读取到+,识别出它是一个加法操作符,并生成一个代表操作符的词法单元。
  7. 读取到数字3,同样识别出它是一个数字常量,并生成一个代表数字常量的词法单元。
  8. 读取到分号;,识别出它是语句的结束符,并生成一个代表结束符的词法单元。

通过这个过程,词法分析器将源代码转换成了一系列的词法单元,这些词法单元随后会被后续的编译器或解释器阶段(如语法分析、语义分析等)使用来构建程序的内部表示或执行程序。

三,语法分析

是编译过程的核心阶段之一,也称为解析。在这一阶段,编译器或解释器将词法分析器产生的词法单元序列组合成符合编程语言语法规则的语法结构,并生成一棵语法分析树(Syntax Tree)或中间表示形式。

AST(Abstract Syntax Tree,抽象语法树)

语法分析树是一种树形结构,其中每个节点都对应于源代码中的一个构造。树的根节点通常表示整个程序或函数,而子节点则表示更小的构造,如表达式、语句块等。通过遍历语法分析树,编译器可以生成机器代码、字节码或执行其他操作,如类型检查、优化等。

在V8引擎中,语法分析器将JavaScript代码转换为抽象语法树(AST),这是一个中间表示形式,用于后续的代码生成和优化阶段。AST包含了源代码的所有结构信息(语句,表达式和声明等等),但不包含源代码的文本内容(空白符注释等等)。

代码执行

当AST被成功构建后,编译器将使用他来进行进一步的语义分析

四,有效标识符

在JScript(通常指的是Microsoft的JavaScript实现,与标准ECMAScript非常相似)中,有效标识符(也称为变量名或标识符)必须遵循一些特定的规则。以下是在JScript中创建有效标识符时需要遵循的基本规则:

  1. 首字符:标识符的第一个字符必须是字母(a-z 或 A-Z)、美元符号($)或下划线(_)。
  2. 后续字符:第一个字符之后,标识符可以包含字母、数字、美元符号或下划线。
  3. 大小写敏感:JScript 是大小写敏感的,因此 variableName 和 VariableName 被视为两个不同的标识符。
  4. 不允许空格:标识符中不允许使用空格。
  5. 避免数字开头:标识符之中可以包含数字,不能以数字开头。
  6. 不能是关键字或保留字:不能使用JavaScript的关键字或保留字作为标识符。例如,varfunctionclassifforwhiletruefalse 和 null 等都是不能用作标识符的关键字。
  7. 不建议使用特殊字符:虽然美元符号 $ 和下划线 _ 可以作为标识符的一部分,但在某些编程风格中,它们可能有特定的含义或用途。例如,下划线前缀的变量名(如 _privateVar)有时用于表示“私有”变量或属性。
  8. 长度限制:尽管实际上没有严格的长度限制,但过长的标识符名可能会降低代码的可读性。
  9. 命名约定:为了提高代码的可读性和可维护性,通常遵循某种命名约定。例如,使用驼峰命名法(camelCase)来命名变量和函数,其中每个单词的首字母大写(除了第一个单词

下面是一些有效的JScript标识符示例:

javascript复制代码
	var myVariable;  

	var myFunction;  

	var _privateVar;  

	var $specialVar;

而以下是一些无效的JScript标识符示例:

javascript复制代码
	var 123name; // 第一个字符不能是数字  

	var for; // for 是关键字  

	var trueValue; // true 是关键字  

	var -variable; // 第一个字符不能是特殊字符(除了 $ 和 _)