说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

全面解析ECMAScript 6模块系统

HTML文档下载 WORD文档下载 PDF文档下载
模块化对任何大型应用来说十分必要,ES6弥补了JavaScript缺少对模块支持的遗憾。浏览器虽对ES6模块化支持还不够,但开发者可以借助编译器将ES6模块转换成ES5。本文将系统讲解ES6模块系统所提供的各种编码方法。

【编者按】在任何一个大型应用中模块化是很常见的。ES6的模块为JavaScript提供了这个特性,并且为这些模块提供了许多选择方法来导出和引入对象。Ravi Kiran 在《Modules in ECMAScript 6 (ES6)》一文中主要讨论了ES6模块系统。以下为该文章的简译内容:

无论使用何种编程语言开发大型应用,最关键的特性就是代码模块化。这个概念在不同的编程语言里有着不同的命名,在C里为头部文件,C++和C#里为命名空间,Java中为包,名称不一样但解决的是同一问题。正如《 ECMAScript 6 – New language improvements in JavaScript》系列文章中第一篇所提到的那样,最初JavaScript并不是用来编写大量代码的,比如创建大型框架、App应用等。就在我们因为JavaScript缺少对模块的支持而编写大量代码时,开源开发者提出了一些标准,如CommoneJs模块模型、异步模块定义(AMD)以及一些库,来实现模块化。在过去几年里,这些库获得了广泛关注,并成功应用到多个企业规模级的应用程序中。

ES6为JavaScript带来了模块特性。浏览器实现这一特性还需要一段时间,因为它们必须定义一个方法来动态下载文件。在浏览器支持该特性以前,我们可以使用编译器,如 Traceur、6to5、ES6 Module Loader以及其它可以让ES6模块转换成ES5的转码器。

JavaScript模块系统的现状

CommonJS模块系统

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

异步模块定义(AMD)

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

TypeScript模块

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

ES6模块系统

ES6模块系统启发于上述现有模块系统,它具有以下特性:

  1. 使用export关键词导出对象。这个关键字可以无限次使用;
  2. 使用import关键字将其它模块导入某一模块中。它可用来导入任意数量的模块;
  3. 支持模块的异步加载;
  4. 为加载模块提供编程支持。

接下来让我们通过具体编程方法看看每一个特性。

导出对象

在现有的模块系统中,每个JavaScript代码文件在ES6中都是一个模块。只有模块中的对象需要被外部调用时,模块才会输出对象,其余则都是模块的私有对象。该处理方式将细节进行封装,仅导出必要的功能。

从模块里导出对象,ES6为我们提供了不同方法,见下面的讨论。

内联导出

ES6模块里的对象可在创建它们的声明中导出。一个模块中可无数次使用export,所有的对象将被一起导出。请看下面的例子:

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(1987, 1, 22));

案例中的模块导出了两个对象: Employee类,getEmployee函数。因对象emp未被导出,所以其仍为模块私有。

导出一组对象

尽管内联导出很有效,但在大规模模块中,它就很难发挥作用了,因为我们可能无法追踪到模块导出来的对象。在这种情况下,更好的办法是,在模块的末尾单独进行导出声明,以导出该模块中的全部对象。

使用单独导出声明重写上一案例中的模块,结果如下:

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(1987, 1, 22));export {Employee, getEmployee};

在导出时,重命名对象也是可以的。如下例所示,Employee在导出时名字改为了Associate,函数GetEmployee改名为getAssociate。

export {    Associate as Employee,    getAssociate as getEmployee  };

Default导出

使用关键字default,可将对象标注为default对象导出。default关键字在每一个模块中只能使用一次。它既可以用于内联导出,也可以用于一组对象导出声明中。

下面案例展示了在组导出语句中使用default:

export default {    Employee,    getEmployee};

导入模块

现有模块可以使用关键字import导入到其它模块。一个模块可以被导入任意数量的模块中。下文展示了导入模块的不同方式。

无对象导入

如果模块包含一些逻辑要执行,且不会导出任何对象,此类对象也可以被导入到另一模块中。如下面案例所示:

import './module1.js';

 导入默认对象

采用Default导出方式导出对象,该对象在import声明中将直接被分配给某个引用,如下例中的“d”。

import d from './module1.js';

 导入命名的对象

正如以上讨论的,一个模块可以导出许多命名对象。如果另一模块想导入这些命名对象,需要在导入声明中一一列出这些对象。举个例子:

import {Employee, getEmployee} from './module1.js';

 当然也可在同一个声明中导入默认对象和命名对象。这种情况下,默认对象必须定义一个别名,如下例。

import {default as d, Employee} from './module1.js';

 导入所有对象

以上几种情况,只有import声明中列举的对象才会被导入并被使用,而其它对象则无法在导入模块中使用。当然,这就要求用户了解哪些对象可以导出并加以利用。如果模块导出大量对象,另一模块想引入所有导出的对象,就必须使用如下声明:

import * as allFromModule1 from './module1.js';

 allFromModule1这一别名将指向所有从module1导出的对象。在导入模块中,它们作为属性可被访问。

可编程式的按需导入

如果想基于某些条件或等某个事件发生后再加载需要的模块,可通过使用加载模块的可编程API(programmatic API)来实现。使用System.import方法,可按程序设定加载模块。这是一个异步的方法,并返回Promise。

该方法的语法示例如下:

System.import('./module1.js')    .then(function(module1){        //use module1    }, function(e){        //handle error    });

如果模块加载成功且将导出的模块成功传递给回调函数,Promise将会通过。如果模块名称有误或由于网络延迟等原因导致模块加载失败,Promise将会失败。

ES6模块使用现状

到目前为止,所有浏览器还不能自然支持ES6模块,所以在浏览器加载之前,我们需要使用转译器(transpiler)将代码转换成ES5。直到现在,我一直使用Traceur作为我的转译器,建议大家使用相同的工具将模块代码转化为浏览器可识别的代码。让我们看看编译ES6模块的几种不同的方法。

使用Traceur动态编译ES6模块

当浏览器加载脚本后,我们可以使用Traceur的客户端库动态编译ES6模块。使用该方法,运行模块无需运行任何命令。我们要做得就是,在页面上加载Traceur库,及添加代码脚本来运行WebPageTranscoder。

<script>    new traceur.WebPageTranscoder(document.location.href).run();</script>

现在,我们就可以在script标签内,将类型指定成模块,以此导入任何一个ES6文件。

<script type="module">    import './modules/import1.js';</script>

类型指定为模块的任何脚本标签将被ES6客户端库获取并处理。上面代码块中的导入语句将发送AJAX请求,捕获相应的JavaScript文件,并载入它。如果模块内部引用了另一个模块,单独的AJAX请求将发出,以加载与引用模块相对应的文件。

使用Traceur命令编译ES6模块

使用Traceur命令可以将ES6模块编译成AMD或者CommonJS模块。这个方法有两大优点。

  1. 模块完成编译,浏览器不必执行额外动作;
  2. 如果应用已经使用ES5及AMD(或CommonJs)模块系统构建了一半,程序的另一半也可以使用ES6,并被编译为这些模块系统中的任何一个,而不是立即把整个应用编译成ES6。

为了使用编译完成的AMD/CommonJs的模块,我们需要包含支持模块系统的库。我个人比较倾向AMD,所以我将在这里介绍一下它。CommonJS模块的步骤和这个差不多。

下面这句命令是用来让包含ES6模块的文件夹编译成AMD,并把它们存储在一个单独的文件夹:

traceur --dir modules es5Modules --modules=amd

使用CommonJs,你需要在上面命令中使用commonjs代替modules。

在这里,modules指的是包含ES6的文件夹,es5Modules指的是输出目录。如果查看es5Modules文件夹下的任何文件,你将看到该AMD定义块。require.js支持AMD,所以我们可以在HTML页面中,使用script引入require.js,并用data-main属性指明开始文件,就像下面这样:

<script src="bower_components/requirejs/require.js" data-main="es5Modules/import2.js"></script>

使用Traceur Grunt Task编译ES6模块

使用命令编译模块很累而且更容易出错。我们可以使用grunt-traceur自动化编译过程。此时,你需要安装NPM包。

npm intall grunt-traceur –save

Grunt任务所需数据与提供给命令的数据一样。下面是任务的一些配置:

traceur: {  options: {    modules: "amd"  },  custom: {    files: [{      expand: true,      cwd: 'modules',      src: ['*.js'],      dest: 'es5Modules'    }]  }}

现在你可以在控制台里使用下面的命令来运行上面的Grunt任务:

grunt traceur

正如你所看见的那样,它和我们使用命令所产生的效果是一样的。

结论

任何一个大型应用中,模块化十分必要。ES6模块为JavaScript提供了该特性,这些模块提供了众多选择来导出和引入对象。我很期待该特性被浏览器支持的那一天,到时我们无需加载任何第三方库即可创建、加载JavaScript模块。目前流行的客户端MV*框架Angular.js在其2.0版本(目前还在开发中)中就使用了ES6的模块化。

让我们开始使用模块系统,从而让我们的代码更具组织和可读性。(编译:肖元州,审校:陈秋歌)

原文链接:Modules in ECMAScript 6 (ES6)

程序流程控制基础 - DOS BAT批处理编程入门教程(四) For循环语句详解 - DOS BAT批处理编程入门教程(五) Android编程之实现GPS定位 android编程实现仿iphone的tab效果 系统变量 - DOS BAT批处理编程入门教程(三) Android编程获取手机的IMEI Android开发中14个很有用的编程技巧 Android蓝牙栈bluez使用方法 Android模拟GPS数据生成kml和nmea文件 Android签名用keytool和jarsigner制作apk文件 谈谈Android中文短信的实现 Android中文短信开发技巧 Android来电号码获取代码 Android AIDL初学者必看内容 Android与XML解析 Android天气预报程序开发实例与定位信息 Android中文短信开发终结篇 Android权限列表permission说明 Android输入法开发实例解析 Android示例程序Snake贪食蛇源代码分析 Android平台View的按键事件KeyDown用法 Android加速感应器实现屏幕自动旋转-Sensor属性 Android视频播放类VideoView解析 Javascript如何检测浏览器关闭了小叉叉 文件操作 - DOS BAT批处理编程入门教程(六) 获得手机中的电话簿 Android开发学习小心得 VC中用CPPToolTip轻松实现工具提示 Android中MediaRecorder类实现视频录制 WEB开发中将数据库记录转换到EXCEL表格文件xls供下载 F#是什么语言 怎样在数据库中输入了许多条记录后, 一次性存盘成功? 改变光驱盘符?很急很急 在Oracle中怎样加已经存在的数据文件? 我想请高手帮忙 !! 请问目前那一本参考书对DELPHI初学者有很大提高? 一个关于udp重发的问题 如何在delphi程序里调用vc写的exe执行文件。 如何将query中的内容输出到文本文件,然后还能将该文本文件再导入进来?急急急!!!!!!!!!!! 急急急!!我的计算机找不到硬盘了45分 如何求任意多边形的重心 紧急求助:请问java有没有比较丰富的多媒体控件?比如录音的控件??? 急急急!!!我的计算机找不到硬盘了,45分 如何把一个字段的内容求和,然后把结果存入另一表! 请教,怎样把一个记录数组用VB读入ACCESS 2000数据库中? 关于货币类型的问题? the script too large ????????我快疯了。 什么地方有Sybase与Oracle的比较资料? 急急急!!!我的计算机找不到硬盘了,40分 问一下大家 复活节彩蛋 win2000 professional下如何配置weblogic6.0 jsp和javasript如何通讯? 急!!!如何把'¥100'字串转化为浮点型100.00 用OleContainer1将一个WORD文档存进数据库后如何将它从数据库中取出??? 关于SNMP的问题(请高手回答,送40分) 谁想过要戒水?戒成了吗?又渴了吗? 我用在各种机器上使用Win2000,从来没有down过, 真是太奇怪了??? 请问如何确定操作系统系统是中文的还是英文的? 向外国用户发注册码时候应该说些什么,才能让别人觉得你比较专业? 如何捕获ADO的异常信息 struct结构的数据存储是用的什么顺序方式呀? 能介绍几本关于BCB的适合初学者阅读的书吗? 高手进来,struct结构的数据存储是用的什么方式呀 高分!高手请进!!! Newton 有关StoredProc的 各位大虾进来看看,Debug时的错误~~~~~~~ First-chance exception 和 User breakpoint ,帮帮我啊!!! 虽然我也回复没有分,但有意思的帖子,但我对分数高的帖子更有热情,我是不是很势利?? 我的服务器是unix 哪位提供最简单的图片存入库中的代码 谁能得到拨号上网所使用的电话的号码? 关于视中图形(非图像)的缩放问题! 想不通啊~~ 谁来帮帮我~~~?? 哪里可以宕到:Robohelp Office(亚洲版),急!! 谁能告诉我PWS怎么用 小弟刚下载了j2sdkee1.2.1 ,但不知道如何配置,那位大哥愿意帮忙,详细讲一讲如何配置。 TOleContainer怎么没有滚动条呀 在哪里可以找到mschart5.cab? 明天在莫斯科将产生2008年奥运主办国,请猜是哪个城市主办!答对者有分!(可加到204) 请问有没有做电力系统方面开发的? IIS是什么 英语翻译Mr.Green was ill and went to the hospital.A doctor lookedhim over and said,“Well,Mr.Green,you are going to get some injections,andyou’ll feel much better.A nurse will come and give you the first one thisevening,and then you’ll have 英语翻译材料:紫菜 2包 青瓜 2条 蟹柳 1包 蛋 3只 白饭 大量 白醋 2汤匙 萝卜 1条 1)先把青瓜,蟹柳,材料:紫菜 2包青瓜 2条蟹柳 1包蛋 3只白饭 大量白醋 2汤匙萝卜 1条1)先把青瓜,蟹柳,萝卜清洗 请帮我把“一切因你而存在、一切因你而精彩”用英语翻译一下!急、简洁点就行、 英语翻译SPACE APPLICATIONInternational Organizer:CP EXHIBITION Rm 1703,Tung Wai Comm'l Bldg109 Gloucester Road,Wanchai,Hong KongPlease fill up the followingdetail:Company (ExhibitorAddress I/We the undersigned wish to participate inthe above exhi 英语翻译大连老菜菜谱1.\x05 溜肝尖 2.\x05 鸡里蹦 3.\x05 猪里蹦 4.\x05 溜鱼片 5.\x05 苏杨大烤 6.\x05 滑溜肉 7.\x05 糖醋小黄花鱼 8.\x05 炒肉拉皮 9.\x05 红油肉 10.\x05软炸虾仁11.\x05 辣肥肠 12.\x05溜肚 你永远是我最美好的曾经 英语翻译 英语翻译The Seller agrees to hold the Buyer harmless against liability and direct (not consequential) cost resulting from infringement of any unexpired United States patent now issued,involving any equipment exclusively designed and manufactured 英语翻译 太棒了!(英文翻译) 英语翻译1.上周末,我和朋友去隔壁县的一个村寨旅游 2.当我们接近那里时,发现它是模仿古代某个城堡而建的.3.它以养鸟而闻名 英文翻译“多谢你的巧克力” 我认为我英语很棒.英语翻译 英语翻译我已经打电话向中国西联汇款咨询过了,叔叔在汇款单上填写我的姓名顺序还是错误的,所以导致汇款现在还是取不到;这是中国西联汇款向我提供的美国西联汇款免费专线:800-325-600 用英语翻译:在书包后面有一些巧克力吗? 英语翻译:我认为他们很棒. 英语翻译Well,here we are.About half a year into our relationship.But as to me,it just feels like we have spent many many years together already for I feel I am a part of you.I can clearly remember our first time together,the way you kissed me,the 巧克力对你的健康有利的英语翻译 英语翻译(你们的孩子永远是最棒的) 英语翻译Don't be sorry,I have loved my life.I have a lovely wife,4 children who will do anything for me and 7 grandchildren that are the loves of my life.I just want to say one thing.I am not sure how experienced you are with the internet but don 巧克力包装盒的英文翻译 英语翻译 你本来看上去很棒 英语翻译我很希望能为你做点什么,同时我也想成为你的笔友.请尽快给我回信.我也想了解关于你更多的情况. 英语翻译One of the few foods which appeals to people all over the world is chocolate.Developed by the Aztecs in South America,chocolate was brought to Europe by Spanish explorers around 1500 and soon became a fashionable drink.By the 19th century 英语翻译This movie __is __ .He is __ it,__. 英语翻译你们好!昨天已经在西联取到了汇款,共:$400美元,谢谢大家对我们的关心,奶奶非常感谢simeona,新年假期完了,现在我也回工厂正常上班了,夏威夷的冬天不冷吧?现在家乡的温度只有8℃ 英语翻译 中国的北京故宫真的很棒!用英语翻译 “xx省xx市人民医院”正规英文翻译 这些美味的蛋糕是给我们的吗用英语翻译 英语翻译1.to show how much we're going to miss her,let's have a surprise party for her next Friday the 28th.2.bring Ms.Steen to the party without telling her so that she can be surprised.3.I look forward to hearing from you all. 我亲爱的笔友.英文翻译 英语翻译:对XX来说这个太大了 我从不吃像蛋糕这样的甜食英语翻译怎么说 "亲爱的" 的英文翻译 英语翻译 给他买个生日蛋糕就足够了 英语翻译 亲爱的英语翻译是什么? “吃一个有葡萄的蛋糕.”用英文翻译? 玛丽正在等待她的生日蛋糕.英语翻译! 英语翻译在动物园里,老虎们正在打架,猴子正在荡秋千,狮子在跑步,小鸟正在天空中飞翔,海豹正在睡觉,豹子正在爬树,狐狸正在地上打滚,蟒蛇正在吞食食物. 喜欢吃蛋糕用英语怎么说 生日蛋糕用英语怎样说 英语翻译自己自己总是假装坚强连流泪也保持嘴角上扬可是,只有自己知道心里一阵隐忍的疼痛怅然无触摸到已如上古的回忆时间早已无痕地偷走我们的青春可你何时才会知道我喜欢你呢? 我们吃些蛋糕好吗?英语翻译 我想要一个插着蜡烛的生日蛋糕英文翻译 英语翻译:你要在昆明待几天呢? 用英语说出果仁巧克力蛋糕制作方法 英语翻译they _____ the birthday of their motherland _____ _____ songs 帮我用英语翻译一下“昆明泰伦信息技术有限公司” "制作巧克力蛋糕的食谱"用英语怎么说 英文翻译 "祝愿所有11月生日的朋友生日快乐" 英语翻译他们来自哪里 他们来自英国么?他们不是来自英国的 .他们来自法国 用DO形式回答 . 黑樱桃巧克力蛋糕用英文怎么写? 英语翻译注意是将要. 用英语翻译:你来自哪里? 巧克力 蛋糕 巧克力蛋糕英语 翻译 最后,人们吃了她妈妈亲手做的生日蛋糕 在招聘信息中的英文翻译 这是人家发来的招聘信息一部分1. Before on board (please reply me ASAP on this part then we can arrange the physical check for you before Chinese New year, because the following process for your onb 英语翻译You’ll need four eggs three tomatoes one onion a little oil salt and pepper first slice the onion and tomatoes next in a frying pan fry the sliced onions and oil until it turns light brown then add the tomatoes after frying the tomatoes 其实大家都知道,我们都不是彼此的那杯茶 上句求英文翻译..麻烦了
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn