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

全面解析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)

《Kingdom Rush Frontiers》上线后 迅速抢占27个国家游戏榜首 移动周报:85后程序员,iOS开源项目,细数7天大事件! Instagram:从Redis到Cassandra 成本节省1/4 乐元素CTO凌聪访谈:游戏引擎技术选型之王道 iOS 7的新设计并非止于外表 WWDC 2013大会10大启示:正向开发者支付大量现金 云计算大会微软专场成功举办 Windows Azure公众预览版上线 IBM全球大裁员 在美国裁员已经开始 动动鼠标,决定“中国十大优秀开源项目”的归属 为改善Flickr 雅虎收购拍照应用开发商GhostBird 让你轻松学习新代码库的六个步骤 RESTful API 设计最佳实践 谷歌11亿美元豪购Waze原因:获取数据 争本地广告市场 为什么大家都要疯狂吐槽iOS 7的扁平化设计? 伟大的程序员是天生的,不是造就的 比Hive高效7倍 Facebook推新一代查询引擎Presto 未来的存储系统设计——PMC技术交流会举行 第五届中国云计算大会PPT尝鲜:十位专家分享的架构实践 “DIY”可穿戴设备:索尼开放智能手表固件 在微软的八个月里,我学到了这些 谷歌实习生每月都拿$6000,你呢? 【第五届中国云计算大会】由瓦特变比特输出,新疆要做中亚云服务中心 应用程序扩展性实现的十宗罪 图文:看谷歌实习生的惬意生活 为移动而设计:交互设计篇 小米游戏中心月度报告:极品、神庙、找你妹 中科院:常温下的液态金属电路3D打印机 细数IE10里的HTML5特性 使用Twitter Bootstrap的五大理由 Twitter重塑API战略 开启V1.1时代 Sony开放SmartWatch 支持第三方定制固件 高手请进 高手请进 开发的结局,一个美丽的谎言!!! 发邮件! 请问! 请问各位高手:汉字转换为拼音,怎么转换? 如何模拟窗口最小化? 怎样才能最有效率的得知RESULTSET对象中没有记录呢? 有谁知道PC104的结构,芯片,CPU等的情况,和适合开发什么应用? MFC dll中 一用了ActiveMovieControl别的程序就不能调用了,怎么解决? 如何在BCB中建立视图? 那天,我被扎了一针 rad hat能不能与windos联机啊、? 惨啊,要跳楼了,谁能帮忙,关于内存泄漏的问题 请问在那里下载VtoolsD开发工具? 为什么ASP页面总是报“HTTP 500 - 内部服务器错误 ” 請問:TC2.0中有無類似于API GetPrivateProfileString()的函數? VB 中如何判断一个对象变量是否被赋值 请问作为标识字段用什么格式好?见者有分!!!! 诚心求教:MDI多视图之间的成员函数调用问题。 请推荐一些有关.net平台的优秀书籍 加密字符串的问题 win2000下无法正常使用localhost来浏览asp页? ★★★如何将一个数字转换成英文写法?急急急!!!★★★ 关于FTP站点下载得问题。。。 STL中有没有左高树?或者菲薄那契堆? 目前,主流的B/S结构的数据库前端开发工具是什么?哪个最有前途? 给我个喜欢VC放JAVA的理由先! 如何解决两个tabpage互换时,tabpage上的控件因检索大量数据而闪烁。 有关dll在设备驱动中的问题。急,在线等待。多谢多谢!! 一个字符串常量"aaa=",一个字符串指针char *m_buffer="bbb",怎样相加得到"aaa=bbb".谢谢! 54beginner java文本框的问题 谁有Dream控件的原码(200分酬谢) 在php+mysql中能不能把数据库文件放到别的目录下! 急 求援!有谁在看<<c++大学教程(第二版)>>电子工业出版社,一道题难住了. 这是为什么???? delphi程序最小化后如何常驻内存执行(在屏幕右下角)? 用sql语句怎样创建自动编号的字段 关于外键???有人说在数据库应用中不应该使用外键,请大家说明自己的观点!! DataEnvironment如何设置相对路径的数据库 在VC中如何利用VFP的GRID控件 问高手,加密过的asp代码,用什么工具可以解码,为什么我这个工具不能用 url.openStream,从主机读取资源的疑问???? 关于外键???有人说在数据库应用中不应该使用外键,请大家说明自己的观点!! 急救,请问 TClientDataSet 的 RefreshRecord如何使用,它起的是什么作用? 窗体的大小不能改变,应怎样设置? 调查:大家说说,自己这辈子打心眼里最对不起的一个人是谁???? 关于WIN2000双启动的问题 请问怎样才能取得指针所在行的行号? 给我足够学习java的理由先! 一箱苹果15千克,进货价:63元1箱.零售价:5.6元1千克.售出这箱苹果盈利多少元? 在绿茵场上,足球运动员带球进攻,总是尽力面向球门AB冲近,然后再射门,从数学的角度说明运动员为什么这样做?为什么? 有101枚硬币,其中50枚是假币,每枚假币在重量上与真币相差1克.现有一带指针的天平,可以显示天平两端所放物品的重量之差,取出一枚硬币,试图用天平做一次称量来确定所取硬币的真假,试分析 一种奶糖每千克十五点六元,买这种奶糖0.5千克、4.6千克应付多少钱? 如图,在绿茵场上.足球运动员带球进攻,总是尽力面向球门AB冲近.(1)在D点的射门角度∠ADB与C点的射门角度∠ACB哪个大?请说明理由.(2)若测得∠1=30º,∠2=20º,∠ACB=50°,请计算出球员在 有101枚硬币,其中100枚质量相同,另一枚是假币.现在不知假币比真币重还是轻(1)利用天平,至少称几次可以判断假币比真币重还是轻?说说你的想法.(2)在上题的基础上,至少称几次就能找出 运算放大器 积分电路中 电容上并联一电阻 此电路什么作用?运算放大器 积分电路 正相输入端接地 输入电压vi经电阻接 反相输入端,电容一段接反相输入端 一端接输出v0 有一电阻和电容并联 如图,在绿茵场上,足球队员带球进攻,总是向球门AB冲近,说明这是为什么? 有101枚硬币,其中100枚同样的真币和1枚伪币,至少几次就能找出假币 上拉电阻 下拉电容那位大虾帮帮我.一个普通的I/O输出口为什么要设置一个上拉+5V和一个下拉电容呢? 用一根长度为150厘米的塑料管和橡皮泥做一个有三条棱长分别为12cm10厘米和8厘米的长方体架子,应如何裁截这根塑料管?8点前就要 给客户的英文拜访邮件!刚进一家外企,接替刚离职的员工的工作,上级要我给客户发邮件做个礼节性的问候,同时为下次登门拜访打好基础,客户基本上都是国内企业,但邮件要用英语的,请问这该 英语翻译翻译引号以内的 “您的账已经到了我们指定的银行,但是因为户名错误,暂时入不了账,需要您去您的银行办理更改收款人户名” 希望快速解决. 英语留言条,“You cannot be at the railway station when your father arrives there.Your friend is going to meet him for you.write a note to your friend."急!内容! 外国客户来访时怎样做公司的英文介绍 英语翻译Excuse me,___ the bank ___? 小明想用一根长度为250厘米的塑料管和橡皮泥做一个三条棱长分别为10厘米、30厘米和15厘米的长方体架子,应如何裁截这个塑料管? 客户这个词语 英语 英语翻译and the Bank to the contray,the Bank may at any time without prior notice modify,cancel or suspend the Facility/Facilities at its sole discretion including,without limitation,canceling any unutilized facilities,and declaring any outstandi 用一根长度为180厘米的塑料管和橡皮泥能否做一个三条棱长分别为15厘米,12厘米和10厘米的长方体架子? 留言条格式谁知道?举例.(要很正规) 英语翻译因为ATM机出现故障或您连续输入密码错误3次,导致您的银行卡被吞了.请您5个工作日后来拿卡.一个星期后我们会通过总行通知您.现在请您填写这张投诉表. 英语 留言条格式 美猴王阅读答案《美猴王》第一部分:1.本文选自         ,作者      ,     小说家,著有      .2.注意下列加点字的读音.迸裂(  ) 瞑目(  ) 七 电工实验报告思考题4、提高电路功率因数为什么只采用并联电容器法,而不用串联法?所并的电容器是否越大越好? 英语留言条小王晚上要请我吃饭 但父母临时要我陪他们去听音乐会 所以去不了要求100字左右 求苏教版语文补充习题美猴王阅读探究习题部分的题目及答案 我们做模电的运放电路实验,有一个思考题:Uo=10U1-5U2能否用一级运放实现,为什么,写实验报告要用. 美丽的西双版纳练习题文章是从哪四个方面介绍西双版纳的? 52集动画片美猴王14那里有的看52集动画片美猴王14几时放知道说下. 磁滞回线思考题实验报告大学物理实验 磁滞回线思考题 交流电频率对磁滞回线有什么影响384153781@qq.com 美丽的西双版纳相关习题由于字数限制所以请打开网页查看课文http://www.sz1z.com/asp/dzyw/ReadNews.asp?NewsID=814问题:示例:西双版纳美,它有像蛇一样的藤状植物.填空:西双版纳美,它有_______________ 别再糟蹋美猴王了(阅读及答案).谢 药剂学实验报告上的思考题.临床上使用甘油栓剂的作用和机理是什么? 根据《美丽的西双版纳》,如何向朋友介绍西双版纳400字左右 英语翻译 关于x的一元一次方程的最简形式是ax=b(a、b表示已知数),当a≠0时,他有惟一的解x=a/b.那么,a为何值时,关于x的方程3(ax-2)-(x+1)=2(1/2+x)有唯一的解?这个解是什么? 电工复杂电路计算方法 计算可以简略 谢谢 初二语文题(美丽的西双版纳)介绍“野象谷的大象”为什么先介绍“热带雨林的树”? 若A,B互为互为相反数,且均不为0,则一元一次方程AX+B等于0的根X等于什么 为什么需要信号运算电路 美丽的西双版纳中最能概括西双版纳特点的句子是 以‘道德’为话题,用提醒,发展,道题,严肃,考虑,这几个词的其中两个写一段话,运用一种修辞手法 电工计算口决 如安 电流如何计算出 有五种品牌不同的奶糖各2千克,从每千克奶糖中各取出1/4,混合在一起,重新包装成一袋.这袋奶糖重()千克,占原有奶糖总质量()/() 中国经济发展面临什么机遇? 电工 计算电流有10台电磁炉,最大功率算2000W,要多粗的线,电流多大 有250千克奶糖,若每袋装四分之一千克,每袋装25袋,可以装多少箱? 我又进步了(品德篇) 作文一篇 《我又进步了(品德篇)》 作文,在品德方面的再次进步,要写出以前的与现在的差别. 小红同学在一支铅笔的下端粘上一块橡皮泥,将它分别置于甲、乙两杯液体中观察到静止时的情形如图3所示,下A.铅笔在甲杯液体中受到的浮力较大B.铅笔在乙杯液体中受到的浮力较大C.乙 上拉电阻和下拉电阻是什么意思? 怎样提高电路的功率因数啊?开关电源应用的电路 在一只新铅笔的一端绕一些铁丝做成简易的密度计,当它漂浮在水中时浸入水中的长度为10.3cm:漂浮在海水中时,浸入海水中的长度为10cm,求海水的密度 用一根长度是80厘米的塑料管和橡皮泥做一个三条棱长5厘米、6厘米、4厘米的长方体架子,应如何截取这根塑料 日光灯电路和功率因数的提高的实验结论是什么 注意:足球运动员在何处射门最好(不考虑人的因素)请给出推倒公式 1.用一根长度为180厘米的塑料管和橡皮泥做一个三条棱长分别为15厘米、12厘米和10厘米的长方体架子,应如何裁截这根塑料管?2.某学生由家到校上课,他先以每小时4千米的速度步行了全程的一 一箱水果糖12千克,进货价:150元/箱,零售价:15元/千克.每千克可盈利多少钱? 如图,在足球比赛中,甲带球向对方球门PQ进攻,当他带球冲到A点时,同伴乙已经助攻冲到B点,此时甲 是直接射门好,还是将球传给乙,让乙射门好?(仅从射门角度考虑) 用数学知识回答 在山的那边是海!这个感叹号有什么作用?用信念凝成的海又 指的是什么
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘