关于循环引用是面试的考点之一,在工作中遇到这种问题确实很少见,但是有必要了解一下。
先理解JS代码执行的过程。
- 引擎:负责整个JavaScript编译及执行的过程
- 编译器:负责语法分析和代码生成
- 作用域:负责收集并维护所有声明的标识符组成一系列的查询系统,确定当前执行的代码对标识符的访问权限(根据名称查找变量的一套规则)
CommonJS 模块是运行时加载(运行时执行一次),ES6 模块是编译时输出接口(编译时执行一次)。
看看下面一个循环引用的例子。
main.js
import a from './a';
console.log(a)
a.js
console.log('执行a')
import b from './b' // 开始编译b模块,代码停留在这里
console.log(b)
console.log('导入b之后')
export default '我是a模块'
b.js
console.log('执行b')
import a from './a' // 由于a模块还在编译阶段,代码并没有执行结果,切记在这里使用结构赋值 let {a} = undefined 会报错的
console.log(a) // 变量是undefined
console.log('导入a之后')
export default '我是b模块'
结果
// 编译阶段
b.js:1 执行b
b.js:3 undefined
b.js:4 导入a之后
// 执行阶段
a.js:1 执行a
a.js:3 我是b模块
a.js:4 导入b之后
main.js:2 我是a模块
ES6根本不会关心是否发生了"循环引用",只是生成一个指向被加载模块的引用,需要开发者自己保证,取值的时候能够取到值。
模块的循环引用本身不会造成代码报错,只是取值的时候可能无法取到值,可以通过一些逻辑判断处理即可。