ECMAScript®2015 语言规范中添加了模块化的功能。而 JavaScript 模块化最依赖的两个语法就是 export 关键字和 import 关键字
- 前者用于导出一个模块中声明的提供给其它模块使用的东西
 - 后者则用于将一个模块中使用 
export导出的东西导入到当前所在的脚本中 
本章节,我们就来讲讲前者,也就是 export 关键字
export 关键字说明
MDN 上对 export 的描述是
export 语句用于在创建 JavaScript 模块时,从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们
理解这句话就要弄懂两个地方,一个是什么是 JavaScript 模块,另一个是可以导出的东西到底有那些 ?
JavaScript 模块
对于什么是 JavaScript 模块 ? 我想,这应该不是一个问题,但是,它其实又是一个问题
JavaScript 模块,通俗的江,就是一个独立的 JavaScript 文件,模块中可以包含一些变量,一些常量,一些类,一些函数,甚至是任何可以执行的代码。
模块 vs 普通脚本文件
创建模块时,一个 JavaScript 模块,跟我们平时写的 JavaScript 文件没什么差别
那么 JavaScript 模块和我们平时编写的普通的 JavaScript 文件有啥区别呢 ?
区别就在于运行时的代理 ( 浏览器或 Node.js ) 是如何对待两者的
- 
对于普通文件,准确的说,是浏览器中的普通脚本文件 ( 因为 Node.js 下不存在普通文件 ),所有的文件级别的声明都是默认全局的,也就是都在
window这个超级变量上 - 
而对于模块,例如
Node.js中的文件,或者浏览器上声明为text/module的文件,文件级别的声明默认是私有的,除非特别说明 ( 使用export导出 ),否则外部的其它文件是无法访问的 
如果要细细说明,那么就会涉及到 export 和 import 两个关键字语法,就会产生鸡和蛋的问题。
所以,我们这里,对模块只有一个定义,就是一个 JavaScript 文件
export 语法
ECMAScript®2015 对 export 的语法做了如下定义
export { name1, name2, …, nameN }; export let name1, name2, …, nameN; // also var export let name1 = …, name2 = …, …, nameN; // also var, const export function FunctionName() {...} export class ClassName {...} export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1, name2, …, nameN } from …; export * from …; export { name1 as default, … }; export { variable1 as name1, variable2 as name2, …, nameN }; export { import1 as name1, import2 as name2, …, nameN } from …;
参数 nameN 表示要导出的标识符(用来被其他脚本的 import 导入 )
当看到这些语法时是不是吓了一大跳,这么复杂...其实,你只要阅读了我的说明,就不会觉得复杂了
你也看到了,我其实是故意将这些语法分为 5 组的,每各分组代表了一种用途
- 
第一组:导出一个模块中声明的东西
大家先想想,对于一个网页中的普通的文件,我们在文件中定义或声明的什么东西才会添加到
window超全局变量上 ?想想 ?
- 使用 
var声明的变量 - 使用 
let声明的不可变变量 - 使用 
const声明的常量 - 使用 
function声明的函数 - 使用 
function*声明的生成器函数 6.. 使用class声明的类 
所以,对于一个 JavaScript 文件,所有能被添加到
window超全局变量上的东西,都能被导出而第一个
export { name1, name2, …, nameN };与后面几个的差别,就相当于是前者先声明这些东西,然后再导出js var name1; const name2; let name3; export name1, name2, …, nameN;后者将声明和导出放到一起
 - 使用 
 - 
第二组:第二组与第一组的差别,就在于
default关键字和export default expression- 
default是默认的意思,export default的意思就是默认导出,也称之为匿名导出,说默认导出你可能不太理解,说匿名导出你应该就理解了,因为JavaScript有匿名函数的存在hello.js
var hello = function(){} export default hello; 
当使用
export default hello的时候,对于导入语法import func from hello,func其实就是hello所以,JavaScript 模块有一条规则,那就是 只能有一个
export defaultJavaScript 模块还有另一个规则,就是 **不能使用
var,let或const作为默认导出- 理解了 
export default那么对于export default expression应该就很好理解了,就是先求取expression表达式的值,然后再export default 
 - 
 - 
export ... from ...对于前面的两组,都是导出export关键字所在的模块中的声明,但export ... from ...则可以导出另一个模块中声明的东西这个语法很有意思,有了这种语法,我们就可以创建子模块功能,然后在同一入口中导出所有公开的声明
假设我们有一个模块
greeting,目录结构如下. |-- index.js |--- hello.js
假设
hello.js中的代码如下export function hello() { return 'Hello World'; }
那么
index.js中就可以使用export hello from hello
对于其它需要使用
greeting模块的项目,只要使用下面的语句就可以使用hello函数import hello from index
 - 
export * from …;,当你看懂了第三组语法,那么第四种语法就很简单了,就是一种偷懒的写法,就是把...文件中导出的声明再次导出,本质上来说,就是export name1,name2,name3,... from ...的简写需要注意的是:
export * from ...不会导出已导入模块中的默认导出,如果要导出已导入模块中的默认导出,需要使用下面的语句import mod from "mod"; export default mod;
 - 
export as语法,我们也称之为别名导出,原来export name1的时候导出的名字是name1,那么使用export name1 as alias1的时候,就是给name1取一个别名alias1然后再导出这个别名 
这 5 组导出方式,我们可以根据有无 default 关键字分类,命名导出 和 默认导出 ,这种划分的原因一方面是因为有无 default 关键字,另一方原因是 import 也会区别对待它们
- 
命名导出对导出多个值很有用。在使用
import导入期间,必须使用相应对象的相同名称 - 
可以使用任何名称导入默认导出,唯一的规则就是 只能有一个默认的导出 ,例如
假设同一个目录下存在两个文件
test.js和main.jstest.js中的内容如下export default k = 12; // in file test.js
main.js中的内容如下import m from './test' // 我们可以自由使用任意标志符来替换 k,比如 m,因为 k 是默认导出的 console.log(m); // will log 12
 
范例
- 
使用命名导出
假设在某个模块
mymodule.js中有如下代码mymodule.js
function cube(x) { return x * x * x; } const foo = Math.PI + Math.SQRT2; export { cube,foo };
那么再其它脚本中,我们可以这样使用
import { cube, foo } from 'mymodule.js'; console.log(cube(3)); // 27 console.log(foo); // 4.555806215962888
 - 
默认导出
如果我们要导出一个值或模块中的返回值,就可以使用默认导出
mymodule.js
export default function cube(x) { return x * x * x; }然后,在另一个脚本中,可以直接导入默认导出:
import cube from 'mymodule'; console.log(cube(3)); // 27
 
浏览器兼容性
虽然 export 是 ES2015 标准规范中的东西,但很遗憾,戒指目前,在很多浏览器中仍然不被支持
此特性目前仅在 Safari 和 Chrome 原生实现,当然也为此除了很多转换器,比如 Traceur Compiler,Babel 或 Rollup
其中以 Babel 最为出名
至于具体的浏览器兼容性,可以查看下表
PC 浏览器
至于浏览器兼容性问题,可以访问
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/export