Web/11-Node.js/JavaScript模块化:ES6.md

325 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: JavaScript模块化ES6
publish: true
---
<ArticleTopAd></ArticleTopAd>
## 模块化开发的引入
### JS开发的弊端
JS 在使用时存在两大问题,而 Node.js 可以很好地避免这两个问题:
- 文件依赖。比如 a 文件依赖 b 文件b 文件依赖 c 文件。而 Node.js 中的文件依赖,不需要人工维护和人为分析。
- 命名冲突。js 的各个文件是相互开放的,容易导致命名冲突。而 Node.js 是属于半封闭的状态,可以指定哪些内容是开放的,哪些内容是封闭的。
Node.js 在解决这两个问题时,用到的就是模块化开发。
### 软件开发中的模块化开发
一个功能就是一个模块,多个模块可以组成完整的应用,抽离一个模块不会影响其他功能的运行。
效果如下:
![](http://img.smyhvae.com/20200409_1934.png)
### Node.js 中的模块化开发
Node.js 规定,一个 JS 文件就是一个模块,模块内部定义的变量和函数默认情况下在外部无法访问。
模块内部可以使用 `exports` 对象进行成员导出, 使用 `require` 方法导入其他模块。效果如下:
![](http://img.smyhvae.com/20200409_1932.png)
## ES6模块化的基本语法
### ES6模块化的说明
**依赖模块需要编译打包处理**。原因如下:
- 1有些浏览器不支持 ES6 的语法,写完 ES6 的代码后,需要通过`Babel`将 ES6 转化为 ES5。
- 2生成了ES5之后里面仍然有`require`语法,而浏览器并不认识`require`这个关键字。此时,可以用 `Browserify`编译打包 js进行再次转换。
推荐学习链接:
- <http://es6.ruanyifeng.com/#docs/module>
### 基本语法:
**导出模块**
```
export
```
**引入模块**
```
import xxx from '路径'
```
## ES6模块化的使用举例自定义模块
### 1、初始化项目
1在工程文件中新建如下目录
```
js
| src
| module1.js
| module2.js
| module3.js
| main.js
index.html
```
2在工程的根目录下新建文件`package.json`,内容如下:
```json
{
"name": "es6-babel-browserify",
"version": "1.0.0"
}
```
### 2、环境配置安装babel 和 browserify等
1安装babel 和 browserify
```bash
npm install babel-cli -g
npm install babel-preset-es2015 --save-dev
npm install browserify -g
```
安装 babel 的详细解释,可以参考本人的另外一篇文章:[ES6的介绍和环境配置](https://github.com/smyhvae/Web/blob/master/10-ES6/03-ES6%E7%9A%84%E4%BB%8B%E7%BB%8D%E5%92%8C%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE.md)
2新建.babelrc
在根目录下新建文件`.babelrc`,输入如下内容:
```
{
"presets":[
"es2015"
],
"plugins":[]
}
```
### 3、编写代码
1module1.js
```javascript
//暴露模块:采用分别暴露的方式
export function foo1() {
console.log('我是 module1 中的 foo1');
}
export function foo2() {
console.log('我是 module2 中的 foo2');
}
export let arr = [1, 2, 3, 4, 5];
```
2module2.js
```javascript
//暴露模块:采用统一暴露的方式
function fn1() {
console.log('我是 module2 中的 fn1');
}
function fn2() {
console.log('我是 module2 中的 fn2');
}
//统一暴露
export { fn1, fn2 };
```
3module3.js
```javascript
//暴露模块:采用默认暴露的方式。
//默认暴露的方式可以暴露任意数据类型,暴露的是什么数据,接收到的就是什么数据
//语法格式export default value;
export default () => {
console.log('我是 module3 中 default 方式暴露的函数');
};
```
这里,我们采取了一种新的暴露方式(默认暴露),在暴露时,加上了`default`这个关键字。代码里暴露了一个箭头函数稍后我们注意在main.js里是怎么引入module3.js的。
注意,我们只能写一次 default也就是说只能进行一次默认暴露。
4module4.jsdefault方式暴露多个属性
```javascript
//暴露模块:采用默认暴露的方式。
//默认暴露的方式可以暴露任意数据类型,暴露的是什么数据,接收到的就是什么数据
//语法格式export default value;
export default {
name: '我是 module4 中 default 方式暴露的属性 name',
foo() {
console.log('我是 module4 中 default 方式暴露的函数 foo');
}
}
```
这里,我们依旧采取了默认暴露的方式,只能写一次 default。代码里暴露了一个对象对象里存放了一个属性、一个方法。稍后我们注意在main.js里是怎么引入module4.js的。
如果我想暴露多个属性、多个对象怎呢很简单把你想要暴露的所有内容都放在default里包成一个对象。你看module4.js就是如此 同时暴露了多个属性&方法。
5main.js
这个是主模块。现在,我们来看一下,它如何引入上面的四个模块。
```javascript
//主模块。引入其他的模块
import { foo1, foo2 } from './module1'; //采用解构赋值的形式进行导入。注意,括号里的对象名,要和 module1 中的对象名一致。
import { fn1, fn2 } from './module2'; //采用解构赋值的形式进行导入。注意,括号里的对象名,要和 module2 中的对象名一致。
import myModule3 from './module3'; //module3 模块是采用 default 方式进行暴露的myModule3 这个名字是我随便起的
import myModule4 from './module4'; //module4 模块是采用 default 方式进行暴露的myModule4 这个名字是我随便起的
//调用module1、module2中的内容
foo1();
foo2();
fn1();
fn2();
//调用module3中的内容
myModule3();
//调用module4中的内容
console.log(myModule4.name); //module4中的属性
myModule4.foo(); //module4中的方法
```
我们可以看出:(具体请看注释,非常重要)
- module1和module2是采用**常规暴露**的形式,在引入它们时,模块名要一致。而且,要求用**对象解构赋值**的形式,而不是用 `import myModule from ...`这种形式(否则会报错 undefined
- module2和module3是采用**默认暴露**的形式,在引入它们时,模块名随便起。
6index.html
在这里引入main.js即可。
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="dist/main.js"></script>
</body>
</html>
```
### 4、编译转换
如果我们不进行转换,而是直接在 index.html 中加载 js/src/main.js是会报错的
接下来,我们就进行转换。
1利用 babel 将 ES6 转换为 ES5
```
babel src -d build //build目录会自动生成
```
上方命令的意思是,将`src`目录下的所有ES6文件转化为ES5文件并放在`build`目录下(`build`目录会被自动创建)。
转化成ES5之后我们发现如果直接在 index.html 中加载`build`目录下的ES5文件也是会报错的因为浏览器不认识`main.js`里的`require`关键字:
![](http://img.smyhvae.com/20180414_1410.png)
于是,我们还要进行一次转换。
2利用`Browserify`编译打包 `build`目录下的 ES5 文件:
```bash
browserify build/main.js -o dist/main.js //dist目录需要手动创建
```
dist/main.js就是我们需要引入到 index.html 里的文件。
以后我们每次修改完ES6的代码就要执行上面的两个命令重新生成新的js文件。
运行效果:
![](http://img.smyhvae.com/20180414_1615.png)
工程文件:[2018-04-13-ES6Demo.rar](https://github.com/qianguyihao/web-resource/blob/main/project/2018-04-13-ES6Demo.rar)
## ES6模块化的使用举例引入第三方模块
下载 jQuery 包:
```
npm install jquery@1 //下载jQuery 1.X 的版本里最新的
```
在main.js 中引入上面的 jQuery
```
import $ from 'jQuery';
```
然后我们就可以通过`$`这个符号去写jQuery的代码了。