124 lines
4.0 KiB
Markdown
124 lines
4.0 KiB
Markdown
---
|
|
title: 模块化编程(1)
|
|
date: 2018-5-6 20:15:26
|
|
tags:
|
|
- JavaScript
|
|
- 模块化
|
|
categories:
|
|
- JavaScript
|
|
---
|
|
|
|
#### 准备知识
|
|
> 网页中`<script>`标签
|
|
> + 如果是src引入一个文件的形式 , 加载这个文件的过程默认是同步的 , 如果引入了多个文件 , 则按照声明的顺序进行加载运行 , 前面的文件尚未加载运行完毕 , 不会加载后面的文件
|
|
<!-- more -->
|
|
> + 从src所指定的地址获取文件的动作是异步的 , 如果前面有未加载完成的脚本 , 那么该脚本即使已经获取到 , 也不会先加载运行
|
|
> + 给script标签添加`async="async"`属性 , 可以指定这个脚本的加载运行以异步方式执行
|
|
> + 在IE当中 , 使用`defer`指定异步方式执行脚本
|
|
|
|
例如 :
|
|
```xml
|
|
<script src="http://localhost:8080/test/demo1.js" ></script>
|
|
<script src="http://localhost:8080/test/demo2.js" ></script>
|
|
```
|
|
如果不加 defer async="async" 的情况下 , demo1.js 和 demo2.js 会顺序加载运行 , 假如demo2.js当中有对demo1.js的依赖 , 那么这种情况下不会出现问题
|
|
|
|
```xml
|
|
<script src="http://localhost:8080/test/demo1.js" defer async="async"></script>
|
|
<script src="http://localhost:8080/test/demo2.js" ></script>
|
|
```
|
|
如果demo1.js由于文件庞大 网络不畅等原因加载缓慢 , 我们可以给demo1.js添加异步加载标识
|
|
这种情况下 , demo2.js将**有可能**先于demo1.js加载运行 , 如果存在依赖 , 将**有可能**报错
|
|
|
|
---
|
|
### 模块化的实现方式
|
|
|
|
JS在很长一段时间内不是一种支持模块化编程的语言
|
|
虽然ES6正式支持了类和模块 , 在nodejs环境下的模块化编程没有问题
|
|
但是能够在浏览器环境中普遍使用还需要很长时间
|
|
所以需要采用其他的方法去模拟实现模块化
|
|
#### 原始写法
|
|
```javascript
|
|
function func1() {
|
|
//...
|
|
}
|
|
function func2() {
|
|
//...
|
|
}
|
|
```
|
|
将若干个函数简单堆积在一起 , 可以认为是一个模块
|
|
但是这种模式是将这些函数对象作为全局变量
|
|
如果函数很多 , 会造成全局变量的污染
|
|
与其他模块也可能发生变量的命名冲突问题
|
|
|
|
#### 对象写法
|
|
```javascript
|
|
var module1 = {
|
|
_count : 0,
|
|
up : function(){
|
|
_count ++;
|
|
},
|
|
down : function(){
|
|
_count --;
|
|
}
|
|
};
|
|
```
|
|
这种写法只讲一个对象作为全局变量 , 一定程度上避免了全局变量的污染
|
|
但是这种写法会暴露所有的模块成员 , 无法做到只有模块内部方法能够访问的局部变量
|
|
|
|
#### 立即执行函数写法
|
|
```javascript
|
|
var module1 = (function(){
|
|
var _count = 0;
|
|
return {
|
|
up : function(){
|
|
_count ++;
|
|
},
|
|
down : function(){
|
|
_count --;
|
|
}
|
|
};
|
|
})();
|
|
```
|
|
这种写法 , 把模块内需要保护的变量作为函数的局部变量 , 在外部无法直接去访问
|
|
可以算是相对科学的写法了 , 之后的几种都是对这种写法的改造和扩展
|
|
|
|
#### 放大模式
|
|
如果一个模块需要分成几个部分写在不同的地方 , 或者说一个模块需要去继承另一个模块 , 就需要使用放大模式
|
|
```javascript
|
|
var module1 = (function(mod){
|
|
mod.biz = function(){
|
|
console.log("我是另外加入的方法");
|
|
}
|
|
return mod;
|
|
})(module1);
|
|
```
|
|
|
|
#### 宽放大模式
|
|
上面的放大模式显然需要保证模块加载的先后顺序
|
|
如果传入的module1是undefined , 肯定会报错
|
|
然而部署在外网的项目 , 如果严格限制了模块的加载顺序 , 很容易造成页面加载缓慢
|
|
为了适应这种情况 , 可以采用宽放大模式
|
|
```javascript
|
|
var module1 = (function(mod){
|
|
mod.biz = function(){
|
|
console.log("我是另外加入的方法");
|
|
}
|
|
return mod;
|
|
})(module1 || {});
|
|
```
|
|
module1模块的两部分都采取这种写法 , 加载的先后就无所谓了
|
|
先加载的会在空对象上添加方法
|
|
|
|
#### 输入全局变量
|
|
一个模块最好能够是独立的 , 不与其他模块中的部分直接进行交互
|
|
但是如果在模块内需要其他模块产生的对象
|
|
可以显式地将这些对象输入到模块内部
|
|
|
|
比如需要用到jQuery的对象
|
|
```javascript
|
|
var module1 = (function($){
|
|
//...
|
|
})(jQuery);
|
|
```
|