common规范的应用
commonjs的特点
commonjs中每个js文件都是一个单独的模块require()方法加载其他模块时,会执行被加载模块中的代码module.exports 指向暴露的对象,exports是简写情况,默认情况下,exports和module.exports指向同一个对象 exports==module.exports,如果不同module.exports为准require() 可以在任意的位置,动态加载(运行时加载)模块,不会提升到最开头需要关注的问题
script标签直接引入的方式,没有模块化,script内部的变量是可以相互渲染的
require、module、exports方法,但是这三个变量在文件中是没有定义的。 Commonjs 会将我们写代码包装起来,形成包装函数,require、module、exports本质是通过形参的方式传递到包装函数中的。require: 引入模块的方法module: 记录当前模块信息exports:当前模块导出的属性require、module、exports等参数const sayName = require('./hello.js')
module.exports = function say(){
return {
name:sayName(),
author:'ranan'
}
}
//包装后
(function(exports,require,module,__filename,__dirname){
const sayName = require('./hello.js')
module.exports = function say(){
return {
name:sayName(),
author:'ranan'
}
}
})
require() 可以在任意的位置,动态加载(运行时加载)模块,不会提升到最开头。module :在 Node 中每一个 js 文件都是一个 module ,module 上保存了 exports 等信息之外,还有一个 loaded 表示该模块是否被加载,没有加载过就先缓存后执行,已经加载过,就直接去缓存不用执行来避免循环引用问题。
/*
根据文件标识符,先查找有没有缓存,有缓存直接返回缓存的内容
没有缓存,创建module对象,将其缓存到module上,然后加载文件,将 loaded 属性设置为 true ,然后返回 module.exports 对象。
*/
// id 为路径标识符
function require(id) {
/* 查找 Module 上有没有已经加载的 js 对象*/
const cachedModule = Module._cache[id]
/* 如果已经加载了那么直接取走缓存的 exports 对象 */
if(cachedModule){
return cachedModule.exports
}
/* 创建当前模块的 module */
const module = { exports: {} ,loaded: false , ...}
/* 将 module 缓存到 Module 的缓存属性中,路径标识符作为 id */
//只会在第一次加载时运行一次,后面都会从缓存中读取,
Module._cache[id] = module
/* 加载文件 */
runInThisContext(wrapper('module.exports = "123"'))(module.exports, require, module, __filename, __dirname)
/* 加载完成 *//
module.loaded = true
/* 返回值 */
return module.exports
}
Es Module
ES6 module 的引入和导出是静态的,import 会自动提升到代码的顶层 import , export 不能放在块级作用域或条件语句中。这种静态语法,在编译过程中确定了导入和导出的关系,所以更方便去查找依赖,更方便去 tree shaking
import 导入的变量是只读的,可以理解默认为 const 装饰,无法被赋值import 导入的变量是与原变量绑定/引用的,可以理解为 import 导入的变量无论是否为基本类型都是引用传递。import() 返回一个 Promise 对象, 返回的 Promise 的 then 成功回调中,可以获取模块的加载成功信息。
特点
import() 动态加载一些内容,可以放在条件语句或者函数执行上下文中if(isRequire){
const result = import('./b')
}
import() 可以实现懒加载[
{
path: 'home',
name: '首页',
component: ()=> import('./home') ,
},
]
import() 可以很轻松的实现代码分割。避免一次性加载大量 js 文件,造成首次加载白屏时间过长的情况。
| - | commonJs | es module |
|---|---|---|
| 导入方式 | require()动态加载模块,可以在任意的位置,不会被提升到最前面 | 导入方式分为静态导入和动态导入 静态导入:不能放在块级作用域和条件中,会提升到最前面 动态导入 import()类似require(),但他是异步加载的 |
| 构建模块依赖的时期 | require同步加载并执行模块文件,CommonJS 模块在执行阶段分析模块依赖。 | 在编译阶段就建立起了模块之间的依赖关系 ES6 模块在预处理阶段分析模块依赖,在执行阶段执行模块 |
| 输出的值 | 输出值的拷贝值,一旦输出了某个值,如果模块内部发生变化,不会影响外部的值 | 输出的是值的引用,JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行的时候,再根据这个只读引用,到被加载的那个模块里去取值。所以内部发生变化会影响外部的值。 |