js在for循环中使用java代码 javascript遍历对象( 二 )


如图 5 所示,模块 A 依赖模块 B,模块 B 又依赖模块 A,模块 A 和 B 分别被 require 语句从上往下分为 2 段,记为 A1、A2、B1、B2 。

js在for循环中使用java代码 javascript遍历对象

文章插图
如图 6 所示,代码块的执行顺序为:A1 -> B1 -> B2 -> A2 。
js在for循环中使用java代码 javascript遍历对象

文章插图
使用不当的问题如果 B2 使用了 A2 导出的变量会怎么样呢?模块 A 的模块对象上不存在该变量对应的属性,获取的值为 undefined 。获得 undefined 虽然不符合预期,但一般不会造成 JS 错误 。
可以看到,由于 require 语句直接分割了执行的代码块,CommonJS 模块的导入导出语句的位置会影响模块代码语句的执行结果 。
ES6 模块ES6 模块[4]借助 JS 引擎实现 。JS 引擎实现了 ES6 模块的底层核心逻辑,JS 运行时需要在上层做适配 。适配工作量还不小,比如实现文件的加载,具体可以看一下我发起的一个讨论[5] 。
模块使用报错ES6 模块使用不当时,由 JS 引擎或 JS 运行时的适配层抛出错误 。比如:
// Node.js 中报错 internal/process/esm_loader.js:74 internalBinding('errors').triggerUncaughtException ^ Error [ERR_MODULE_NOT_FOUND]: Cannot find module // 浏览器中报错 Uncaught SyntaxError: The requested module './child.js' does not provide an export named 'b'第一个是 Node.js 适配层触发的内部错误(不是通过 throw 抛出的),第二个是浏览器抛出的 JS 引擎级别的语法错误 。
模块执行顺序ES6 模块有 5 种状态,分别为 unlinked、linking、linked、evaluating 和 evaluated,用循环模块记录(Module Environment Records)[6]的 Status 字段表示 。ES6 模块的处理包括连接(link)和评估(evaluate)两步 。连接成功之后才能进行评估 。
连接主要由函数 InnerModuleLinking[7] 实现 。函数 InnerModuleLinking 会调用函数 InitializeEnvironment[8],该函数会初始化模块的环境记录(Environment Records)[9],主要包括创建模块的执行上下文(Execution Contexts)[10]、给导入模块变量创建绑定[11]并初始化[12]为子模块的对应变量,给 var 变量创建绑定并初始化为 undefined、给函数声明变量创建绑定并初始化为函数体的实例化[13]值、给其他变量创建绑定但不进行初始化 。
对于图 3 的模块关系,连接过程如图 7 所示 。连接阶段采用深度优先遍历,通过函数 HostResolveImportedModule[14] 获取子模块 。完成核心操作的函数 InitializeEnvironment 是后置执行的,所以从效果上看,子模块先于父模块被初始化 。
js在for循环中使用java代码 javascript遍历对象

文章插图
评估主要由函数 InnerModuleEvaluation[15] 实现 。函数 InnerModuleEvaluation 会调用函数 ExecuteModule[16],该函数会评估模块代码(evaluating module.[[ECMAScriptCode]]) 。ES6 规范并没有明确说明这里的评估模块代码具体指什么 。我把 ES6 规范的相关部分反复看了至少十余遍,才得出一个比较合理的解释 。这里的评估模块代码应该指根据代码语句顺序执行条款 13[17]、条款 14[18] 和 条款 15[19] 内的对应小节的“运行时语义:评估(Runtime Semantics: Evaluation)” 。ScriptEvaluation[20] 中的评估脚本(evaluating scriptBody)应该也是这个意思 。可以看到,ES6 规范虽然做了很多设计并且逻辑清晰和自洽,但仍有一些模棱两可的地方,没有达到一种绝对完善和无懈可击的状态 。
对于图 3 的模块关系,评估过程如图 8 所示 。和连接阶段类似,评估阶段也采用深度优先遍历,通过函数 HostResolveImportedModule 获取子模块 。完成核心操作的函数 ExecuteModule 是后置执行的,所以从效果上看,子模块先于父模块被执行 。


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: