模块化的简单包装
1 | var module = (function() { // 利用了自执行函数的封闭性 |
1 JS模块化发展历史
- CommonJS 和 AMD CMD 鼎足之势 (前) ES6 (后)
(知名框架 Node.js、RequireJS前置加载 和 Seajs就近加载 分别对应前三个) - 谈谈现阶段:
- ES6标准发布后,module成为标准,标准使用是以
export
指令导出接口,以import
引入模块。 - 在我们一贯的node模块中,我们依然采用的是
CommonJS
规范,使用require
引入模块,使用module.exports
导出接口。是同步
加载 JS 脚本。这么做在服务端毫无问题,因为文件都存在磁盘上,然而浏览器的特性决定了 JS 脚本需要异步加载,否则就会失去响应,因此 CommonJS 规范无法直接在浏览器
中使用。
- ES6标准发布后,module成为标准,标准使用是以
2 对于es6模块的看法(参考阮一峰老师)
es6标准
将成为服务器和浏览器端模块化的通用解决方法
运行时加载
:代码运行到这个语句的时候才会加载编译时加载
:打包工具编译js时,就会去分析模块之间的依赖关系,所以不能放在任何条件代码块里。层级最优先es6模块中的this指向是undefined,不要轻易用this, CommonJs中的this指向当前模块
export的使用,如果需导出的模块前面没有export,那在export的时候就要加上{}
1
2function fn() {}
export {fn}export导出语句是动态绑定的,如果导出的值发生变化,那import进的值也会随之变化
1
2
3
4
5
6
// exportJs
export var foo = 'bar';
setTimeout(function(){ () => foo = 'baz'; },500);
那么foo变量值将在500ms后变成baz字符串,这点与`commonJS`不一样,commonJs是会缓存值。import
命令具有提升效果,会提升到整个模块的头部并首先执行,但还是建议放在头部写比较好。1
2foo();
import {foo} from 'module'; // right*号指定整体输出的一个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// circle.js
export funciton fn1(){
}
export function fn2(){
}
// main.js 需要引入cilcle.js
import * as circle from './circle';
// 调用:
circle.fn1();
circle.fn2();export 的default输出,默认输出
1
2
3
4
5
6
7
8// exportJs
export default function(){
console.log('foo')
}
// importJs
import customFn from './exportJS'
customFn();import函数大括号的写法时机
export后面接着default的时候,不用大括号,没接着的时候是要大括号的。1
2
3
4
5
6
7// 无 default
export function fn1() {}
import { fn1} from 'exportJs';
// 有default
export default function fn2() {}
import fn2 from 'exportJs'因为静态分析没有运行时加载那么“动态化”,所以,import有个提案,目前可以在webpack使用,可以动态输入一个较为狭窄的路径,然后返回一个promise对象
这个情况下的import是支持按需加载
,条件加载
,和动态的模块路径
。1
2
3
4
5
6
7
8const main = document.querySelector('main')
import('./someModule/${someVariable}.js')
.then(module => {
module.loadPageInfo(main)
})
.catch(err => {
mian.textContent = err.message;
})script标签的defer和async属性差异,两者都是取消了js的同步属性。
但是defer是渲染完再执行
,而async是下载完就执行
。待验证:es6模块在网页上的加载
1
2
3<script type="module">
import utils from './util.js';
</script>es6模块,导出的变量不可以重新赋值,但可以添加或修改属性,就是内存地址不能改,里面存的内容随你改,待验证。
1
2
3
4
5
6
7
8// lib.js
export let obj = {}
// main.js
import { obj } from 'lib'
obj.prop = 123; // right
obj = {} // typeError使用
import
命令加载commonJS
模块,Node会自动将module.exports
当成模块的默认输出,即等同于export default
1
2
3
4
5
6
7
8
9
10
11
12
13// b.js
module.exports = null;
// es.js
import foo from './b.js'
import * as bar from './b.js'
// bar = {default: null}
import { somethimg } from 'fs' // error!!!
import * as express from 'express'
const app = express.default() // rightcommonJs
的加载原理
commonJs每个模块都是一个脚本文件,Node内部用require命令第一次加载就会执行这个脚本,然生成一个对象,这个会缓存,即是多次require,不清缓存下,都取第一次。1
2
3
4
5{
id: '', // 模块名
exports: {}, // 导出模块,
loaded: true // 是否加载过
}循环加载:模块之间相互引用
CommonJs会出现,输出已执行的部分,未执行的部分不会输出
es6模块则不会报错
参考文章:
掘金
阮一峰es6 模块篇章
- 本文标题:JS模块化
- 本文作者:Jonnzer
- 创建时间:2020-01-04 14:29:41
- 本文链接:https://jonnzer.github.io/2020/01/04/JS模块化/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!