而默认暴露由于只需要暴露一个接口,所以直接内置了一个默认接口default,既作为模块输出接口,又作为模块内部变量名字,所以默认暴露可以暴露字面量,底层也符合输出接口和模块内部变量的一一对应关系。
export{}是作为一个整体的语法存在,在{}中放入的是模块需要对外暴露内部变量,在形式上其实这里{}更像是一个数组,其数组元素就是模块内部变量。
统一暴露export{}
export
// b.js
var b = function(){
console.log('b')
}
export {b}
exportdefault
需要特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
我们可以通过JS代码编译成的AST抽象语法树来验证ASTexplorer
默认暴露exportdefault
MDN对于export导出的东西描述的很含糊,阮一峰大神在极力试描述清楚export导出的东西,反复地使用了“对外接口”,“值得引用”,“静态定义”,“动态引用”这几个词。
导出的到底是啥?
其次分别暴露和统一暴露可以统称为具名暴露,即它们暴露的接口必须有名字,否则就会报错。而默认暴露的接口可以没有名字。
用法注意
统一暴露的语法export{}中{}是一个对象吗?
var m = 1;
export {m};
所以模块就是指JS文件,这没啥好争议的。
阮一峰教程
需要特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
我还是感觉阮一峰对于’模块‘和’模块的导出‘一直没说清楚,老是将两者混淆,不知道是用词不当,还是词不达意。
分别暴露export
在创建JavaScript模块时,export语句用于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过import语句使用它们。被导出的绑定值依然可以在本地进行修改。在使用import进行导入时,这些绑定值只能被导入模块所读取,但在export导出模块中对这些绑定值进行修改,所修改的值也会实时地更新。TheexportstatementisusedwhencreatingJavaScriptmodulestoexportlivebindingstofunctions,objects,orprimitivevaluesfromthemodulesotheycanbeusedbyotherprogramswiththeimportstatement.Thevalueofanimportedbindingissubjecttochangeinthemodulethatexportsit.Whenamoduleupdatesthevalueofabindingthatitexports,theupdatewillbevisibleinitsimportedvalu
另外具名暴露不能暴露字面量,即没有变量名的值,因为它们需要体现和模块内部变量的一一对应关系。
如上,很多人错误的理解{m}为是一个对象,且使用了对象的简写形式,其实不然。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个JS文件,里面使用export命令输出变量。
而export{}的提出,可以在表面上实现基于模块内部变量表达式形式的导出。
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
阮大神一下子给这么多定义,其实想表达的就是一个意思:export输出的不是一个具体数据,即不是模块内部的变量的值,而是对变量的引用。
ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。比如,CommonJS模块就是对象,输入时必须查找对象属性。
其实这是我们一直以来口误导致的认识错误,所谓变量,其实只有在声明时的一瞬间有,声明过后,不管是单独使用,还是作为实参传递,它都是作为一个表达式,而不是变量。
有人肯定会有疑问,export1中1确实不是变量,可以理解报错,但是exportm中m就是变量啊,为什么还会报错?
MDN的介绍
export,export{},exportdefault这三个导出命令,导出的东西到底是啥?
JS引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6的import有点像Unix系统的“符号连接”,原始值变了,import加载的值也会跟着变。ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
相当于
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
我觉得无论是CommonJS还是ES模块都是指JS文件,每一个JS文件都是一个模块,因为每个JS文件只要被当成模块引入,就会形成一个模块作用域。即JS文件中的变量不会污染到全局。
而提供export{}命令的原因,更多的是解决export命令的不足,因为export必须要求和模块内部变量一一对应,这就需要export命令后面必须跟着声明式语句,而不能是表达式,限制性太高。
JS引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6的import有点像Unix系统的“符号连接”,原始值变了,import加载的值也会跟着变。ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
所以下面的代码报错原因都是:export后面跟的不是变量
// 报错
export 1;
// 报错
var m = 1;
export m;
会被解析器解析为AST抽象语法树
这里“引用”,困扰了我很久,因为阮大神一直在强调export命令输出的东西是在编译时确定的
当前需要搞清楚的是ES6模块的导出,即JS文件中export命令导出的是啥?
CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用。
我们已经知道CommonJS模块的导出modulexports是一个对象了,阮一峰也明确说了ES6模块的导出,即JS文件中export命令输出的东西不是一个对象,而是一个对外接口,是一个值得引用,是一个静态定义,是一个动态引用。
实际上exportdefault底层还是定义了一个接口,该接口的名字是default
第二个差异是因为CommonJS加载的是一个对象,该对象只有在脚本运行完才会生成。而ES6模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
阮一峰自己也在文章里面说了
在阮一峰的ES6教程中关于export命令有这么一个注意点
“引用”不应该是运行时产生的东西吗?说到引用,我就想到了对象,而对象必须是在运行期间产生的,所以引用这个词有歧义。阮大神后面又给出了一个更加确切的名词:“符号连接”
默认暴露和上面两种暴露最大的区别是,一个模块中默认暴露只能使用一次,而export和export{}可以使用多次。
而默认暴露主要场景就是,针对一个模块只暴露一个接口的场景,此时我们需要对比export和export{}只暴露一个接口的场景
export
文章为作者独立观点,不代表股票交易接口观点