四. 前端模块化

1. 为何须要模块化

1.1 JavaScript原始功能

在网页开发的早期js制做做为一种脚本语言,作一些简单的表单验证或动画实现等,那个时候代码仍是不多的。那个时候的代码是怎么写的呢?直接将代码写在 <script> 标签中便可。javascript

随着ajax异步请求的出现慢慢造成了先后端的分离,客户端须要完成的事情愈来愈多代码量也是与日俱增。为了应对代码量的剧增,咱们一般会将代码组织在多个js文件中进行维护。html

可是这种维护方式依然不能避免一些灾难性的问题,好比全局变量同名问题以下面的案例。另外这种代码的编写方式对js文件的依赖顺序几乎是强制性的,当js文件过多好比有几十个的时候弄清楚它们的顺序是一件比较同时的事情,并且即便你弄清楚顺序了也不能避免下面案例出现的这种尴尬问题的发生。前端

image-20201129123915750
1.2 匿名函数的解决方案

咱们可使用匿名函数来解决方面的重名问题,在aaa.js文件中咱们使用匿名函数。java

(function(){
	let flag = true
})()

可是若是咱们但愿在main.js文件中用到flag应该如何处理呢?显然另一个文件中不容易使用,由于flag是一个局部变量。这样又有了代码不可复用的问题。node

1.3 使用模块做为出口

咱们可使用将须要暴露到外面的变量,使用一个模块做为出口es6

来看下对应的代码:咱们作了什么事情呢?ajax

  • 很是简单,在匿名函数内部定义一个对象。
  • 给对象添加各类须要暴露到外面的属性和方法(不须要暴露的直接定义便可)。
  • 最后将这个对象返回,而且在外面使用了一个MoudleA接受。
var ModuleA = (function() {
	//1.定义一个对象
	var obj = {};
	//2.在对象内部添加变量和方法
	obj.flag = true;
	obj.myFunc = function(info) {
		console.log(info);
	}
	//3.将对象返回
	return obj;
})

接下来咱们在man.js中怎么使用呢?咱们只须要使用属于本身模块的属性和方法便可后端

if(ModuleA.flag) {
	console.log('小明是个天才!');
}
ModuleA.myFunc('小明长的真帅!');
console.log(ModuleA);

这就是模块最基础的封装,事实上模块的封装还有不少高级的话题。可是咱们这里就是要认识一下为何须要模块以及模块的原始雏形。异步

幸运的是,前端模块化开发已经有了不少既有的规范以及对应的实现方案。常见的模块化规范:CommonJSAMDCMD,也有 ES6 的 Modules模块化

2. 模块化开发相关规范

模块化有两个核心:导出和导入

2.1 CommonJs规范

注:CommonJs规范依赖于node环境(node底层会解析CommonJs规范的导入和导出)

CommonJS的导出

module.exports = {
    flag: true,
    test(a,b) {
        return a + b;
    },
    demo(a,b) {
        return a * b;
    }
}

CommonJS的导入

//CommonJS模块
let {test, demo, flag} = require('moduleA');

//等同于
let _mA = require('moduleA');
let test = _mA.test;
let demo = _mA.demo;
let flag = _mA.flag;
2.2 ES6的export命令

解决命名冲突问题

在经过script标签引入js文件时添加一个 type=module,表示使用这个文件是一个单独的模块。而单独的模块有本身的做用域,此时里面的内容必须经过ES6的导出命令才对外部可见(能够经过ES6的导入命令使用)。

<script src="a.js" type="module"></script>
<script src="b.js" type="module"></script>

export指令用于导出变量

//info.js
export let name = 'why';
export let age = 18;
export let height = 1.88;

还有另外一种写法

//info.js
let name = 'why';
let age = 18;
let height = 1.88;

export {name, age, height};

导出函数或类

上面咱们主要是输出变量,也能够输出函数或者输出类

export function test(content) {
	console.log(content);
}

export class Person {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	
	run() {
		console.log(this.name + '在奔跑')
	}
}
function test(content) {
	console.log(content);
}

class Person {
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	
	run() {
		console.log(this.name + '在奔跑')
	}
}

export {test, Person}

export default

某些状况下一个模块中包含某个功能,咱们并不但愿给这个功能命名,而是让导入者能够本身来命名
这个时候就可使用 export default

//info.js
export default function () {
	console.log('default function');
}

咱们来到main.js中这样使用就能够了。这里的myFunc是我本身命名的,你能够根据须要命名它对应的名字

import myFunc from './info.js'

myFunc();

注意:export default在同一个模块中不容许同时存在多个。

2.3 ES6的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, info.height, info.friends);
相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息