为什么需要模块化
JavaScript原始功能
在网页开发的早期,js作为脚本语言,做一些简单的表单验证或动画等,代码量很少。
随着ajax异步请求的出现,慢慢形成了前后端分离,客户端需要完成的事越来越多,为了应对代码量的剧增,通常会采用多个js进行维护,但这种方式,依然不能避免一下灾难性问题
比如全局变量同名的问题
// a.js文件中,小明定义了一个变量
var flag = true;
// b.js文件中,小红又重新定义了flag变量
var flag = false;
// c.js文件中,小明想通过flag做一些事情
if (flag) {
console.log(1111)
}
// 小明发现代码不能正常运行,但是自己在a.js中确实定义的true,bug就不容易被解决
// 演示代码只是举例,实际代码中每个文件都可能有很多代码,一个一个文件去找也不现实
这种编写方式对js文件的依赖顺序几乎是强制性的,但当js文件过多时,想要弄清它们的顺序也是比较麻烦的,而且即使弄清了,全局变量同名的问题可能还是会发生。
匿名函数的解决方案
可以使用匿名函数来解决重名的问题
比如在a.js文件中,使用匿名函数
(function() {
var flag = true
})()
但又有另外一个问题,想在c.js文件中使用flag,怎么处理呢?
使用匿名函数后,a.js中的flag就变成了一个局部变量
使用模块作为出口
可以将需要暴露到外面的变量,使用一个模块作为出口
var ModuleA = (function() {
// 1. 定义一个对象
var obj = {}
// 2. 在对象内部添加变量和方法
obj.flag = true
obj.func = function(info) {
console.log(info)
}
// 3. 将对象返回
return obj
})()
上面代码中,在函数内部定义了一个对象,将需要暴露到外面的属性和方法添加到对象中(不需要暴露的直接定义即可),最后将对象返回,并且在外面使用ModuleA接收
接下来,在c.js中,只需要使用属于自己模块的属性和方法
if (ModuleA.flag) {
console.log(1111)
}
console.log(ModuleA.func('测试信息'))
这就是模块最基础的封装,这里简单认识一下为什么需要模块以及模块的原始雏形
现在前端模块化开发已经有了很多规范:
CommonJS、AMD、CMD以及ES6的Modules
CommonJS
模块化有两个核心:导出和导入
CommonJS的导出
module.exports = {
flag: true,
sum(a, b) {
return a + b
}
}
CommonJS的导入
let {flag, sum} = require('moduleA')
ES6中模块化的使用
export指令
export基本使用
export指令用于导出变量
// info.js
export let name = '小明'
export let age = 18
export let height = 1.8
另一种写法
// info.js
let name = '小明'
let age = 18
let height = 1.8
export {name, age, height}
导出函数或类
分开导出
export function sum(a, b) {
return a + b
}
export class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
run() {
console.log(this.name + '正在跑步')
}
}
一起导出
function sum(a, b) {
return a + b
}
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
run() {
console.log(this.name + '正在跑步')
}
}
export {sum, Person}
export default
某些情况下,一个模块中包含某个功能,我们并不希望给这个功能命名,而是让导入者自己命名,这个时候可以使用export default
// info.js
export default function(argument) {
console.log(argument);
}
导入者使用
// main.js
import test from './info.js'
test('info');
注意:export default在同一个模块中,不允许同时存在多个
import指令
使用export指令导出了模块对外提供的接口,下面就可以通过import指令来加载对应的模块了
首先,需要再HTML代码中引入两个js文件,并且类型需要设置为module
<script src="./info.js" type="module"></script>
<script src="./main.js" type="module"></script>
import指令用于导入模块的内容
// main.js
import {name, age, height} from './info.js'
console.log(name, age, height)
如果希望某个模块中的所有信息都导入,一个个导入会很麻烦,这时就可以通过*导入模块中的多有export变量,通常情况下需要给*起一个别名,方便后续使用
import * as info from './info.js'
console.log(info.name, info.age)