目标:了解一下前端模块化的知识

内容:用于记录一些心得。(前端模块化)

正文:

一、JavaScript原始功能

  在网页开发的早期,JS作为一种脚本语言,做一些简单的表单验证或者动画实现,那个时候代码还是很少的,一般是直接写在< script>标签中。

二、存在问题

  随着AJAX异步请求的出现,慢慢形成了前后端的分离。客户端需要完成的事情越来越多,代码量也是与日俱增。为了应对代码量的剧增,我们通常会将代码组织在多个JS文件中,进行维护。但是这种维护方式,依然不能避免一些灾难性的问题。比如说全局变量同名问题(因为一个大的项目是多人完成的,需要导入每个人写的代码汇总);另外,这种代码的编写方式对JS文件的依赖顺序几乎是强制性的,也无法避免全局变量同名问题。

三、模块化雏形(早期的模块化)

  之前解决上述的问题的方法有匿名函数,类似于(function () {} )()的格式。但是代码的复用性又不得不降低了,甚至不可复用。所以在ES5中可以通过把需要可复用的代码添加到一个对象,通过匿名函数的返回这个对象(使用模块作为出口,暴露到外面的属性和方法,不需要暴露的直接定义),并用某个变量去接收这个返回对象,这个变量就是模块。然后在别的文件导入这个模块,就可以使用这个模块的代码了。

  幸运的是,前端模块化开发以及有了很多既有的规范,以及对应的实现方案。

  常见的模块化规范有:CommonJS(通过node实现),AMD,CMD,也有ES6的Modules。(tips:模块化包括导出和导入)

四、CommonJS(webpack也使用这个,因为也是依赖node环境)

  CommonJS的导出:(注意是要在node环境下,要用node底层解析module.exports)

1
2
3
4
5
6
7
8
9
module.exports = {
flag: ture,
test(a, b) {
return a + b
},
demo(a, b) {
return a - b
}
}

  CommonJS的导入:(moduleA是刚刚导出文件的文件名(可加路径))

1
2
3
4
5
6
7
//CommonJS模块
let {test, demo, flag} = require('moduleA')
//等同于
let _mA = require('moduleA');
let test = _mA.test;
let demo = _mA.demo;
let flag = _mA.flag;

五、ES6的Modules

  export(导出)/import(导入)

  当我们在引入别人JS文件时,用< script src=”xxx.js’>,当我们在script标签下使用type=‘module’时,这意味着我们是按照模块化使用这个xxx.js文件。相当于这个文件是在一个模块内,有着自己独立的作用域。

  export(导出了模块对外提供的接口)。可以导出变量,函数,类(ES6提供了class类)。或者是导出一个默认的东西,让导入者自己来命名(export default),这样的好处就是导入者可以不必知道要导入的模块代码的名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//info.js
export let name = 'coco'
export let age = 18
//另一种写法
// let name = 'coco'
// let age = 18
// export {name, age}
export function logInfo (value){
return console.log(value)
}
export class Person {
constructor(name, age){
this.name = name;
this.age = age;
}
run(){
console.log('I am a class')
}
}
// export logInfo, Person}
//默认导出只能有一个
const address = 'abc';
export default address

  import(导入,加载对应模块)。导入之后就可以对应使用了。通过可以导入模块中所有的export变量,但是通常情况下我们需要个用as起一个别名,方便后续使用。

1
2
3
4
5
6
7
//func.js
import {name, age} from 'info.js'
import{logInfo, Person} from 'info.js'
//默认导出adress并命名为add
import add from 'info.js'
//import * as info from './info'
//console.log(info.name, info.age)