全面解析ECMAScript 5和ECMAScript 6模块系统

ECMAScript 5模块系统

1、CommonJS模块系统(require和export)

CommonJs是一个由开源开发者组成的团队,主要围绕JavaScript实现一些API及开展研发实践。该团队提出了一个JavaScript模块规范。每个文件都可当作一个模块,并且每个文件可以访问两个对象:require和export。require用来接收字符串(模块名),并返回该模块输出的对象。export对象用来导出该模块的方法和变量。require方法返回的就是export对象。模块同步加载。服务器端JavaScript引擎Node.js就是用的这个模块系统。

2、AMD异步模块定义(define)

AMD是一个采用异步方式加载依赖模块的模块系统。如果模块在不同文件中,它们将采用XHR进行加载。某一模块将等其所依赖的模块一一加载后才会被执行。AMD模块必须是一个函数,并作为参数传入define函数中。函数的返回值将传输给所有依赖的模块,所获得返回值又将作为参数传给模块方法。Require.js库中实现了AMD。

3、TypeScript同步加载模块(export module、import)

TypeScript,作为JavaScript的超集,也提供了一个模块系统。当它被编译时,便开始使用JavaScript模块模式。TypeScript模块使用module关键字定义,任何被输出的对象必须使用export关键字定义。import关键字用来将其它模块加载入模块中,并捕捉该模块导出的对象。TypeScript模块是同步加载的。

ES6模块系统

ES6模块系统启发于上述现有模块系统,它具有以下特性:
1、使用export关键词导出对象。这个关键字可以无限次使用;
2、使用import关键字将其它模块导入某一模块中。它可用来导入任意数量的模块;
3、支持模块的异步加载;
4、为加载模块提供编程支持。
接下来让我们通过具体编程方法看看每一个特性。
导出对象
在现有的模块系统中,每个JavaScript代码文件在ES6中都是一个模块。只有模块中的对象需要被外部调用时,模块才会输出对象,其余则都是模块的私有对象。该处理方式将细节进行封装,仅导出必要的功能。
从模块里导出对象,ES6为我们提供了不同方法,见下面的讨论。
内联导出
ES6模块里的对象可在创建它们的声明中导出。一个模块中可无数次使用export,所有的对象将被一起导出。请看下面的例子:
<pre>export class Employee {
constructor(id, name, dob){
this.id = id;
this.name=name;
this.dob= dob;
}
getAge(){
return (new Date()).getYear() - this.dob.getYear();
}
}
export function getEmployee(id, name, dob) {
return new Employee(id, name, dob);
}
var emp = new Employee(1, "Rina", new Date(1994, 9, 15)); </pre>

案例中的模块导出了两个对象: Employee类,getEmployee函数。因对象emp未被导出,所以其仍为模块私有。
导出一组对象
尽管内联导出很有效,但在大规模模块中,它就很难发挥作用了,因为我们可能无法追踪到模块导出来的对象。在这种情况下,更好的办法是,在模块的末尾单独进行导出声明,以导出该模块中的全部对象。
使用单独导出声明重写上一案例中的模块,结果如下:
<pre>class Employee {
constructor(id, name, dob){
this.id = id;
this.name=name;
this.dob= dob;
}
getAge(){
return (new Date()).getYear() - this.dob.getYear();
}
}
function getEmployee(id, name, dob) {
return new Employee(id, name, dob);
}
var x = new Employee(1, "Rina", new Date(1994, 9, 15));
export {Employee, getEmployee};</pre>
在导出时,重命名对象也是可以的。如下例所示,Employee在导出时名字改为了Associate,函数GetEmployee改名为getAssociate。
<pre>export {
Associate as Employee,
getAssociate as getEmployee
}; </pre>
Default导出
使用关键字default,可将对象标注为default对象导出。default关键字在每一个模块中只能使用一次。它既可以用于内联导出,也可以用于一组对象导出声明中。
下面案例展示了在组导出语句中使用default:
<pre>export default {
Employee,
getEmployee
}; </pre>
导入模块
现有模块可以使用关键字import导入到其它模块。一个模块可以被导入任意数量的模块中。下文展示了导入模块的不同方式。
无对象导入
如果模块包含一些逻辑要执行,且不会导出任何对象,此类对象也可以被导入到另一模块中。如下面案例所示:
<pre>import './module1.js';</pre>
** 导入默认对象**
采用Default导出方式导出对象,该对象在import声明中将直接被分配给某个引用,如下例中的“d”。
<pre>import d from './module1.js'; </pre>
** 导入命名的对象**
正如以上讨论的,一个模块可以导出许多命名对象。如果另一模块想导入这些命名对象,需要在导入声明中一一列出这些对象。举个例子:
<pre>import {Employee, getEmployee} from './module1.js'; </pre>
当然也可在同一个声明中导入默认对象和命名对象。这种情况下,默认对象必须定义一个别名,如下例。
<pre>import {default as d, Employee} from './module1.js'; </pre>

** 导入所有对象**
以上几种情况,只有import声明中列举的对象才会被导入并被使用,而其它对象则无法在导入模块中使用。当然,这就要求用户了解哪些对象可以导出并加以利用。如果模块导出大量对象,另一模块想引入所有导出的对象,就必须使用如下声明:
<pre>import * as allFromModule1 from './module1.js'; </pre>
allFromModule1这一别名将指向所有从module1导出的对象。在导入模块中,它们作为属性可被访问。
可编程式的按需导入
如果想基于某些条件或等某个事件发生后再加载需要的模块,可通过使用加载模块的可编程API(programmatic API)来实现。使用System.import方法,可按程序设定加载模块。这是一个异步的方法,并返回Promise。
该方法的语法示例如下:
<pre>System.import('./module1.js')
.then(function(module1){
//use module1
}, function(e){
//handle error
}); </pre>

如果模块加载成功且将导出的模块成功传递给回调函数,Promise将会通过。如果模块名称有误或由于网络延迟等原因导致模块加载失败,Promise将会失败。
结论
任何一个大型应用中,模块化十分必要。ES6模块为JavaScript提供了该特性,这些模块提供了众多选择来导出和引入对象。我很期待该特性被浏览器支持的那一天,到时我们无需加载任何第三方库即可创建、加载JavaScript模块。目前流行的客户端MVC框架Angular.js在其2.0版本(目前还在开发中)中就使用了ES6的模块化。
让我们开始使用模块系统,从而让我们的代码更具组织和可读性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容