拿声明语句来说,具有声明数据名字的语句,也有在声明名字的同时声明块的语句。
在所有的单语句中,都不能使用 let/const 来进行数据声明。
for (let x; ;) let i = 0;
在循环表达式 for 语句中使用 let/const 声明数据,是存在「形式分块」的,并且在每次循环中都会初始化一个相应的环境实例, 但是不可以在单语句中使用 let/const 来进行数据声明。
for (let x;;){
let i = 0;
}
因此,在 JavaScript 中,事实上只能在「形式分块」中进行数据声明。
函数声明语句可以在声明变量名的同时,声明一个形式分块,函数声明会向「所在的块」注册一个名字。
?在 JavaScript 中,声明语句是在语法分析期进行解析和处理的,而不是在执行期发生的。所有的声明语句都会导致 JavaScript 在语法分析期构建相应的名字表,例如 varNames 或 lexNames。这些名字表需要在实际执行代码块之前,在代码块的实例化阶段进行声明实例化。
JavaScript 中有多种形式的分块,包括全局 (Global)、块 (Block)、函数 (Function)、模块 (Module) 和 Eval 块。这些分块都有相应的「声明实例化」过程,用于处理声明语句在名字表中所登记的项。
函数声明的形式分块包括函数名和参数名,函数名会在 varNames 中进行登记。而模块声明的形式分块具有特殊性。因为模块的使用机制约定,同一模块的多次 import 会共享同一个块和环境。因此,模块的形式分块不是由 import 语句创建的,而是由 JavaScript 引擎在装配所有模块的过程中创建的。
在 ES6 之前,JavaScript 的代码由许多函数、语句和模块构成。
所有的代码都是片段,没有顺序关系。JavaScript在逻辑上只是按照连续顺序执行这些代码段。
在这个时期,没有约定代码块何时以及如何被装载到程序中。因此,JavaScript通常在执行之前先进行语法分析,然后从第一条语句开始执行,即使这条语句看起来并不合理或引用了一个未定义的变量。
var test = function(){}
100
yest()
其中,第一行是一个声明语句,第二行是一个单值表达式语句,第三行是一个函数调用。
第二行可能是代码拼写错误,也可能是开发人员有意使用回车符来分割代码,第三行可能是在调用 yest() 函数,也可能是在调用上面 test() 函数,输入的时候拼写错误,这可能会导致代码分析的困难。
由于缺乏程序入口的概念,也没有约定源代码文本的处理方式,JavaScript 在不同的宿主程序中采用自己的方式来处理应用程序、单元模块和模块依赖等概念,这导致了 JavaScript 引擎无法对代码进行有效的、可预期的分析。
但从 ES6 开始,模块的概念被提出。模块通常是扩展名为 .js 的文件,采用了不同于 ES6 之前的惯例。从此时开始,所有具有「声明语句」的代码要么是在声明标识符,要么是在声明块。
更重要的是,ES6 约定所有模块都必须在语法分析期处理。
这意味着 ES6 更加偏向于结构化语言的设计方向,更偏向于实现为静态语言。这为进一步的类型化做准备,并且只有在语言本身可以进行静态语义分析的情况下,类型推导、预编译、执行期优化等特性才能更方便地被应用到 JavaScript 中。
这是结构化程序设计对于大型程序设计语言的价值所在,随着程序规模的扩大,更加结构化的组织代码成为语言设计的必备。
题图生成:Midjourney
内容优化:ChatGPT
内容来源:《JavaScript 语言精髓与编程实战》
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34597.html