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

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

GitLab获400万美元A轮融资,GitLab 8.0将很快到来 【CTO讲堂】如何构建高可用和可伸缩的架构? 未来程序员会被机器取代吗? React Native实战(一):配置和起步 集聚MDCC 2015 免费展位第二波正式放出 【深入浅出Koa】入门知识,带你以现代化开发方式构建Web应用 升级到Node V4的七个理由 支持大量ES6特性 像写SQL一样编写Java数据应用 Swift 2.0实战:如何实现从非零下标遍历数组? 手把手教学:在iOS 8中使用Cocoapods 交互技术前沿与应用实战:MDCC虚拟现实专场议程揭晓 解密“攻城狮使用手册” 技术专家齐聚!MDCC 2015精彩日程全曝光 基于ActiveMQ的消息中间件系统 OneMM逻辑与物理架构设计详解 John Carmack大神亲操刀,为Oculus开发Netflix应用 React Native实战(二):Android的打包 独立游戏的成功秘诀:好设计才是王道 Swift 2.1的新变化 Apple TV实战:用TVML开发第一款tvOS应用 【SDCC讲师专访】阿里王晶昱:云时代的分布式数据库DRDS 硬件研发、嵌入式技术演进:MDCC IoT峰会日程揭晓 专访百度知道iOS团队负责人孙源:代码强迫症的死实践派 TIOBE 2015年10月编程语言排行榜:Ruby取代Objective-C进前十 【SDCC讲师专访】PingCAP联合创始人兼CEO刘奇:好的产品应开源,不闭门造车 【深入浅出Koa】常用工具分享 帮你降低编程难度 Relay: 全新的React数据获取框架 探索游戏开发面临的技术挑战——MDCC 2015游戏开发专场议程曝光 【SDCC讲师专访】易开发创始人潘俊勇:这些年我遇到的那些坑 【CTO讲堂】OpenStack行业实践和发展趋势探讨 万物互联,移动为先:MDCC 2015移动开发者大会盛大开幕! 【MDCC 2015】微软开发体验与平台事业合作部大中华区DX部门总经理Srikanth Raju:物联之上云+端 使用VBScript编程下的类型转换问题 如何遍历主窗体中的每个菜单项!!!不是简单的问题 请问,用程序怎样调用Recongnition Profile的功能? 各位,怎样读取XML格式的配置文件,请给出源代码。急需!!! 关于sco unix5。05的软件的问题 这个文件如何解压:steven.advprog.tar.Z 这个问题很怪的!! 兄弟们,救急啊,关于调用oracle的... jive高手 jive 论坛安装后,为什莫我把Locale Settings 改为中国在论坛的首页报错 调用存储过程的方法,在线等待... 请问各路英雄...??? 在DLL中创建多线程的问题? 着急啊!!!一个关于多文档的问题 install expression 打包问题 急急急 求教 一个框架结构的左右两边同时改变的问题 ★★ 高兴送分 ★★(zzwu) 请教高手 系统重装,SQL 6.5只剩下几个data目录下的dat文件,请问怎么才能把数据完全恢复? 客户端调试sql server存储过程 兄弟我想换工作,还企盼网友推荐(看在我对java版热心参与,请版主保留几天) 如何配置jConnect连接Sybase数据库?需要安装jdk吗? 如何在模块中编写一个函数,对数据库进行增,删,修改操作? a 请问各位DirectDraw是做什么的?最好能详细谈谈他的前景?谢谢! 我的win2000server在域中,被以域中Administrator进入,结果我的机子以域用户进入后,机子的系统关机选项变为不可用,以域中Administrato b/s应用程序怎样限制它只能安装在某一台电脑上? FORM中,如何通过 ODBC 访问 Foxpro的 dbf 数据文件(在线等待)? 如何判断连接服务器的sql数据库成功与否?在线等待高手解答! applet waiting online 程序员招聘(西安) 怎样让我的对话框程序实现全屏显示急急急1。。。 我的用法是否正确 有本事的就进来 JSP+JDBC环境中如何配置jConnect连接Sybase数据库?需要安装jdk吗? 急,高分求解Font问题 我编写了一个读写COOKIE的公用函数在我的工程中使用,老不通过,麻烦大哥们帮我诊断诊断 请问怎样获取托盘窗体的句柄??(给一百分) 请帮帮忙,如何调用dtswiz.dll 如何用BDE Administrator设置数据库别名(不用ODBC)访问Oracle数据库。高分相送! 对不起,我知道这个问题很简单,但是我一直没有搞出来,您能告诉我吗?datagrid中进行insert,delete,update操作? 寻求eVC用ADO操作cbd数据库的代码。 两个关于枚举类的问题 问用过struts的朋友一个问题,给100分! huffan交流系数表在C中如何表示?????? 线程问题~~~ 有哪位知道在 Windows 2000 下 锁定计算机时应用程序可以得到什么消息啊? 急!!关于数据的导入导出!! Cells不被VB支持吗? 获取字段类型 如何将DataGrid1中的数据打印出来, 如何使程序自动修改CEdit中的文字? IPDI是什么物质 沼气:如何产生? 在很多影视剧中,日本人在称呼一些中国人时总要在姓后加一个桑字. 受到核辐射,身体会出现什么症状? 证明地转偏向力的存在的小实验,1就地取材2实验简单,操作性强3体验实验过程,要有实验记录(实验材料,实验结论)4要有实验结果5语言规范,描述准确 800字左右 日本人称呼"桑"用英文怎么写?如:田中桑. 没有核辐射症状,是不是就没有被核辐射家人7月份从日本回来身体一直没有异样,请问这就说明没有被核辐射 怎么证明有地转偏向力的实验 日本人称桑是什么意思 用Mg,AI分别跟稀H2SO4反应,制取相同质量H2,消耗Mg和AL的质量比为?提示 Mg+H2SO4===MgSO4+H2|,2AL+3H2SO4===AI2(SO4)3+3H2| |为气体符号 地转偏向力究竟应该用物理知识解释? 日本桑是什么意思 将10g由Mg、Al、Fe组成的混合物与40ml稀H2SO4恰好完全反应,产生5.6L(S.T.P)氢气,则三种金属的物质的量之和可能为A.0.125mol B.0.2mol C.0.25mol D.0.5mol 设计一个简便易行的小实验,证明地转偏向力的存在 脂肪族聚异氰酸酯属于氨基树脂吗?氨基树脂相关定义:本类树脂由胺或酰胺与醛(甲醛、糠醛等)缩聚而成.最重要的有尿素树脂(如脲甲醛)、硫脲树脂(如硫脲甲醛)、密胺树脂(如密 Mg和HNO3反应 与 MG和H2SO4的反应相同么? 两个220v 40w 220v 110w的电阻接在电压可调的电路中,串并联电路消耗的最大总功率之比 聚异氰酸酯是属于有机树脂吗?有机树脂的定义是什么呢?聚异氰酸酯有哪些化学特性和毒性呢? 中国的盆地(4个)山脉(11条)高原(4个)平原(3个)都叫什么名? 盐酸伪麻黄碱加氢痒化钠混合后会变成麻黄碱吗,麻烦给个化学式如果不能,怎么把盐酸伪麻黄碱变成麻黄碱? 聚异氰酸酯树脂有哪些危害? 谁知道写这些题 谁知道怎么写? 水性异氰酸酯胶黏剂,封闭异氰酸酯在烘干加热时解封出的异氰酸酯会和水反应,怎么保证和树脂的羟基交联?封闭型水性异氰酸酯交联剂常温下可与水性树脂(水性聚氨酯、水性丙烯酸酯、氟 谁知道这个甲骨文这么写? 请问一下大家谁知道毛笔写字课教案怎么写?真的很急了,十分谢谢大伙 精子存活时间,精子的存活期 谁知道有关希腊神话故事的作文编写啊?老师要我们写的... 谁知道1到10大写怎么写啊 精子体外存活期额.那天我同学来我家(女),在她到之前,遗精了,然后不知道有没有洗手,洗手的话洗的掉吗?如果没洗手她如果用我碰过的东西.如果正处于排卵期? 地八大题第 谁知道2题这么写 高中阶段的化学中接触到的沉淀有那些有特殊的颜色?主要是除了白色以外的颜色 精子在体外能存活多久?昨天晚上做的时候有点事就停下来了,但是龟头上好象射了一点出来了但是没射在里面,中间也没洗,但是3分钟后又做了一次.我就是想问如果龟头上有精子的话,再次进入 关于武则天历史小故事知道的话,有急用! 高中阶段涉及的化学离子与沉淀颜色最好能全面一点 (2/2)一直保护我心免受伤,可宝贝我视而不见 因了我感觉到的爱,为之奈何 把上面的汉语翻译成英语. 历史对武则天的评价 将两只标有“220V 40W”的灯泡串联后接在 220 V的电路中,则两灯消耗的总功率为A.80WB.20WC.30WD.40W 语文、关联词xxxxxxxxxxxx除非xxxxxxxxx必定xxxxxx 武则天的历史对武则天的详细说明,还有武则天的事迹 吊水进空气会怎样 神经递质为什么不是内环境成分? 谁知道咋写 癸丑桑松木命 日主参断《癸丑 衰地》戌亥空亡是什么意思 神经递质是否是内环境组成成分 谁知道怎么写呀? 将14g铁粉与足量的硫粉隔绝空气加热,使其充分反应,最多可得到硫化亚铁多少克? 为什么在磁铁内部磁感线是从S到N极,而外部却是相反?RT mg铜和足量的浓硫酸反应,生成SO2nL,则被还原的硫酸是( )A.m/64 mol B.m/32 mol C.n/11.2 mol D.n/22.4 mol答案上写的是A,但A和D不是一样的吗? 谁知道我的春节怎样写? 脂肪族腈类化合物活性为什么比芳香族腈类高呢 从小肠壁流出的血液所含成分特点是营养物质变(),氧气变()食物中的()()()等营养物质不能被人体 直接吸收,要通过多种()的作用下分解成可吸收的物质 如图为小娟家洗手间的部分电路,白炽灯L上标有“220V 40W”字样,L正常工作时电阻为____________.该电路存在的安全隐患是____________.小娟改进电路后.想到家人常忘记关灯,便把标有“220V 60W” 为什么芳香族羧酸比脂肪族羧酸容易发生脱羧反应 血浆里含有那些营养成分谢谢喽 钠的化学性质及其应用? 餐饮废油回收处理属于哪个部门 异佛尔酮二异氰酸酯IPDI我做的木粉和聚乳酸共混,想添加IPDI,不知道IPDI一般添加为填料的百分之几呀? 如何证明地转偏向力的存在? 英语翻译主要是要有汉语什么读的,不然知道什么写不知道什么读
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘