一、JS的演变:
1、简单的页面控制,改变HTML标签和CSS样式
2、AJAX异步请求,控制前后数据传输问题
3、更强大的功能,几乎依赖JS实现
工程管理问题:
简单页面只需要在页面嵌入script标签里面写JS即可完成业务功能的实现
继续向下复杂,JS不得不需要独立出来放入文件中加载实现
JS文件与日剧增,文件也不好管理,引申出模块化概念
实际上倒不如说是为了多人开发的解决方案
二、变量冲突问题
演示案例:
这里引入了三个JS文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="text/javascript" src="devA.js"></script> <script type="text/javascript" src="devB.js"></script> <script type="text/javascript" src="devC.js"></script> </body> </html>
A文件:
// devA var name = 'devA-name' var age = 100 function sum(n1, n2) { return n1 + n2; } var flag = true; if (flag) { console.log(sum(100,8)); }
B文件:
// devB var name = 'devB-name' var age = 23 function sum(n1, n2) { return n1 + n2; } var flag = false; if (flag) { console.log(sum(20,8)); }
C文件引用这个变量进行判断
if (flag) { console.log('flag is true'); }
打印结果:
三、演变与CommonJS
解决上述冲突的方案
var moduleA = (function() { /* 3、 利用这个匿名函数将对象赋值给变量ModuleA */ // devA var name = 'devA-name' var age = 100 function sum(n1, n2) { return n1 + n2; } var flag = true; if (flag) { console.log(sum(100,8)); } /* 1、 利用JS对象把上述的属性和函数装载 */ var object = {}; object.flag = flag; object.sum = sum; console.log(object); return object; // 2、 把这个对象用匿名函数返回 })(); /* 这样全局对象就存放了一个moduleA变量 */
devC文件调用时这样编写:
if (moduleA.flag) { console.log('flag is true'); }
我们模块化之后只需要保证模块对象的变量名称不发生冲突且规范即可
上述的解决方案体现出了模块化的核心概念:
那就是导入和导出【Import & Export】
常见的模块化规范:
CommonJS
AMD
CMD
ES6 Modules
1、CommonJS
规范使用语法:
CommonJSexport.js 导出
module.exports = { flag : true, sum : function () { // todo ... }, }
module.exports是不存在的变量,所以需要API支持
CommonJSimport.js 导入:
【支持.js后缀省略】
let { flag, sum } = require('./CommonJSexport');
上面的写法时使用解构函数
当然还是使用变量引用的方式舒服些
let customModule = require('./CommonJSexport');
四、ES6的模块化导入和导出
导出的JS文件:
var foo = 100; var bar = function () { // todo.... console.log('sss'); } /* 将此JS的变量导出 */ export { foo, bar }
导入的JS文件:
import { foo, bar } from './exportJavaScriptFile.js';
console.log(foo);
bar();
index.html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="module" src="./exportJavaScriptFile.js"></script> <script type="module" src="./importJavaScriptFile.js"></script> </head> <body> </body> </html>
注意上面的script标签一定要使用type属性标注module
否则关键字export和import都无效,浏览器无法解析识别
导出的语法:
/* 将此JS的变量导出 */ export { foo, bar } /* 导出方式二 */ export var varA = 100; /* 导出函数 */ export function fun1() { // todo ... return 100; } /* 导出JS类 */ export class JsClass { aaa; bbb; fun1() { } fun2() { } }
上述的导出在导入时必须使用解构函数,也就是在括号中调用变量名称即可
但是如果是使用导入的类的话,就需要这样使用了。。。
import { JsClass } from './exportJavaScriptFile.js'; let jsClass = new JsClass(); jsClass.aaa = 111; // todo ....
当然我们也希望直接以对象的方式引用出来
可以这样:
// import { foo, bar } from './exportJavaScriptFile.js'; import * as aaa from './exportJavaScriptFile.js'; console.log(aaa.foo); console.log(aaa.bar());
五、Export Default使用
我们不希望把导出的东西进行命名,命名的规则留给导入此模块的调用者去命名
所以有了export default
在上面的案例我们都发现,export之后,导入进来调用的使用者必须按照指定变量名称使用
如果调用者不知道变量名称将是个头疼的事情
但是要注意,export default只允许使用一次。
let foo = 213; let bar = function (n1, n2) { return n1 * n2; } export default { foo, bar }
导入时:
可以自行定义导入模块的变量名称了
import mmm from './defaultExport';
console.log(mmm.foo);
console.log(mmm.bar(213, 332));