ES6 Module在项目中的用法研究

前置条件

3月份我和一位做技术的朋友聊天。
这人不修边幅,油腻腻的,典型的程序员形象。
但是就这样一个人,从他喉咙里出来的每个技术名词,都将我KO得无地自容。
回忆一段对话如下:
-你知道ES6吗?
-我知道。
-你用的多吗?
-现在的项目里在用(内心:其实就用了箭头函数)…
-那你知道babel吗?
-…那是什么?
接着对方使用了unbelievable? excuse me? WTF?等词汇的肢体语言回复了我这个问题,I see 我们对于彼此此刻的judge已经成型了。

回到办公室,搜索了一下babel,是一个超级简单0难度的工具,人生啊,很少机会给你碰到死在一个庞然大物的践踏下,死在星球毁灭人类灭亡的历史中…我的这种死法,太不壮观了,太尴尬了,我死于安逸。

Babel 是一个 JavaScript 编译器。将下一代JavaScript代码转换成浏览器兼容的JavaScript代码。
我和我的团队,长久的使用浏览器兼容的JavaScript代码,生活在自己构筑的稳定世界中,是时候伸出头看看这个世界了。

本文的中心

之前的文章《使用闭包函数优化思维,重构代码》中,有对es6的箭头函数进行了尝试运用,并已经使用在现在的项目中,加上我也过了一遍前辈阮一峰先生的《ES6标准入门(第三版)》电子版,所以es6的一些使用特性,新增的方法属性那些一定是需要你在使用的过程中进行日积月累,因此本文的中心,我focus到我比较关心的module,这是之前js不具备的功能。

es6 module 概述

摘抄一段:
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
我一定要学会的理由:
我没有用过学过CommonJS 和 AMD,直接学ES6 Module一次取代两项技能,怎么都觉得自己赚了,嘤嘤嘤。

语法和使用

export & import

export命令用于规定模块的对外接口
import命令用于输入其它模块提供的功能
一个模块(module)就是一个独立的文件,该文件内部的所有变量,外部无法获取,如果希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。外部文件就得使用import命令加载这个模块的接口

export语法简略

export 命令处于模块文件顶层,不出现在块级作用域内。

export 可输出变量,函数和类

export 可自定义输出的变量或者函数的名字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 输出单个变量,把export 关键字放在变量定义之前,如下:
export let a = 1;
export let b = 2;
// 或者如下输出单个变量,语法强调大括号是必须存在的: export的目的是输出接口,必须和模块内的变量建立一一的对应
let c = 1;
export {c}
// 基于上面的语法释义,输出多个变量如下:
let d = 1, e = 2;
export {d, e};
// 简单吧,输出函数和类的原则同上
// 输出单个函数或类
export function v1() { ... }
export class c1 { ... }
// 或者
function v2() { ... }
class c2 {}
export {v2};
export {c2};
// 输出多个函数或类
function v3() { ... }
function v4() { ... }
class c3 { ... }
class c4 { ... }
export {v3, v4, c3, c4}
// 自定义输出命名
let f = 'f';
function v5() { ... }
class c5 {}
export {
f as varibleF,
v5 as functionV5,
c5 as classC5
}
import 语法简略

导入就是导入,记住语法就行了,不要多想乱写,如下
import {接口1, 接口2, 接口3, … 接口n} from ‘模块文件路径’

我并不会再多说其它什么了,睁大眼睛看好记住,这就是import的语法。

小试牛刀

1 创建一个小项目如图,项目中包含两个文件a.mjs, b.mjs(mjs后缀,我们这里理解为module javascript)。
效果图

2 我们在a.mjs中使用export语法输出接口,代码如下

1
2
3
4
5
6
7
8
9
10
let name = 'Xiao Nai Miao',
describle = 'she has been falling in mad love with a guy';
function getGuyInfo() {
return {
name: 'Xiao Nai Gou',
describle: 'sooooooo sweet and charming~'
}
}
export {name, describle, getGuyInfo};

3 我们在b.mjs中使用import语法接收a模块的输出接口,并且使用这些接口对象

1
2
3
4
import {name, describle, getGuyInfo} from './a.mjs';
console.info('A girl’s name is ' + name + ', and ' + describle + ' named ' + getGuyInfo().name + ' , because ' + getGuyInfo().name + ' is ' + getGuyInfo().describle);

4 目前我学会的使用方式

1) nodejs 加载
首先你的确保你本地的nodejs是最新的版本,使用node -v查看版本号,我的是v9.10.1
最新的nodejs版本已经开始支持es6 module, 但是它要求你的module文件后缀名是‘mjs’,因此从一开始创建项目我就遵循了这个规则
现在我们在cmd进入创建项目【es6-module】的根目录,键入node运行es6 module 的如下命令:

1
node --experimental-modules b.mjs

因为我们在b.mjs导入了a.mjs的借口,并使用了它的数据,所以我们执行b.mjs文件。

执行结果如下:
效果图

A girl’s name is Xiao Nai Miao, and she has been falling in mad love with a guy named Xiao Nai Gou , because Xiao Nai Gou is sooooooo sweet and charming~

YES! 看来我们成功了!

2) es6模块转码之ES6 module transpiler
ES6 module transpiler是 square 公司开源的一个转码器,可以将 ES6 模块转为 CommonJS 模块或 AMD 模块的写法,从而在浏览器中使用。

首先,在本地安装这个转码器。

$ npm install -g es6-module-transpiler

然后,使用compile-modules convert命令,将 ES6 模块文件转码。
-o参数可以指定转码后的文件名。

$ compile-modules convert -o out.js file1.js

现在我们在cmd进入创建项目【es6-module】的根目录,按照上面的转码语法,键入如下命令并且回车:

1
compile-modules convert -o index.js b.mjs

这句命令的意思将b.mjs转码成新的文件,它的名字我命名为index.js

效果图
没有任何报错信息表示转码成功,这个时候你去看你的项目目录,将会显示转码成功后的index.js。

效果图

打开index.js文件,它合并了a.mjs和b.mjs, 变成了我们熟悉的es5的味道。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(function() {
"use strict";
let $$a$mjs$$name = 'Xiao Nai Miao',
$$a$mjs$$describle = 'she has been falling in mad love with a guy';
function $$a$mjs$$getGuyInfo() {
return {
name: 'Xiao Nai Gou',
describle: 'sooooooo sweet and charming~'
}
}
console.info('A girl’s name is ' + $$a$mjs$$name + ', and ' + $$a$mjs$$describle + ' named ' + $$a$mjs$$getGuyInfo().name + ' , because ' + $$a$mjs$$getGuyInfo().name + ' is ' + $$a$mjs$$getGuyInfo().describle);
}).call(this);
//# sourceMappingURL=index.js.map

这个文件可以被任意的浏览器识别和运行,是的,就那么简单!

未完待续

到这里,es6 moudle 算是初步入门了,后面的路且长,愿在实践中获得成长。