--- title: JavaScript模块化:ES6 publish: true --- ## 模块化开发的引入 ### 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,进行再次转换。 推荐学习链接: - ### 基本语法: **导出模块**: ``` 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、编写代码 (1)module1.js: ```javascript //暴露模块:采用分别暴露的方式 export function foo1() { console.log('我是 module1 中的 foo1'); } export function foo2() { console.log('我是 module2 中的 foo2'); } export let arr = [1, 2, 3, 4, 5]; ``` (2)module2.js: ```javascript //暴露模块:采用统一暴露的方式 function fn1() { console.log('我是 module2 中的 fn1'); } function fn2() { console.log('我是 module2 中的 fn2'); } //统一暴露 export { fn1, fn2 }; ``` (3)module3.js: ```javascript //暴露模块:采用默认暴露的方式。 //默认暴露的方式可以暴露任意数据类型,暴露的是什么数据,接收到的就是什么数据 //语法格式:export default value; export default () => { console.log('我是 module3 中 default 方式暴露的函数'); }; ``` 这里,我们采取了一种新的暴露方式(默认暴露),在暴露时,加上了`default`这个关键字。代码里暴露了一个箭头函数,稍后,我们注意在main.js里是怎么引入module3.js的。 注意,我们只能写一次 default,也就是说,只能进行一次默认暴露。 (4)module4.js:(default方式暴露多个属性) ```javascript //暴露模块:采用默认暴露的方式。 //默认暴露的方式可以暴露任意数据类型,暴露的是什么数据,接收到的就是什么数据 //语法格式:export default value; export default { name: '我是 module4 中 default 方式暴露的属性 name', foo() { console.log('我是 module4 中 default 方式暴露的函数 foo'); } } ``` 这里,我们依旧采取了默认暴露的方式,只能写一次 default。代码里暴露了一个对象(对象里存放了一个属性、一个方法)。稍后,我们注意在main.js里是怎么引入module4.js的。 如果我想暴露多个属性、多个对象怎呢?很简单,把你想要暴露的所有内容,都放在default里,包成一个对象。你看module4.js就是如此, 同时暴露了多个属性&方法。 (5)main.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是采用**默认暴露**的形式,在引入它们时,模块名随便起。 (6)index.html: 在这里引入main.js即可。 ```html Document ``` ### 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://download.csdn.net/download/smyhvae/10348940) ## ES6模块化的使用举例(引入第三方模块) 下载 jQuery 包: ``` npm install jquery@1 //下载jQuery 1.X 的版本里最新的 ``` 在main.js 中引入上面的 jQuery: ``` import $ from 'jQuery'; ``` 然后我们就可以通过`$`这个符号去写jQuery的代码了。