前端模块化的好处都已经被说烂了,概括为两点:html
ES2015终于引入了模块的概念,最近学习了下,顺便记下笔记。前端
index.html
<!DOCTYPE html> <html> <head></head> <body> <h1>import</h1> <script src="index.js" type="module"></script> </body> </html>
index.js
export
export
语句导出该模块输出的变量;export
语句有两种语法格式:命名导出, 默认导出。命名导出就是明确导出的变量名称和值。git
在目录下建立math.js,内容以下:github
// Case 1: export后面跟变量输出声明语句 export var PI = 3.14; // Case 2: export后面直接跟变量定义语句 export var add = function (x, y) { // 导出函数print return x + y; }
这表示math.js模块导出变量PI
和add
。用NodeJS的模块格式可表示为:浏览器
var PI = 3.14; var add = function (x, y) { // 导出函数print return x + y; } module.exports.PI = PI; module.exports.add = add;
index.js内容:模块化
import * as Math from "./math.js"; // import是导入模块,后面会说。 console.log(Math.PI); console.log(Math.add(1, 2));
用浏览器打开页面,看看输出结果是否OK:函数
3.14
3
// 调整math.js内容 var PI = 3.14; var add = function (x, y) { return x + y; } export { PI, add }; // 简写格式,统一列出须要输出的变量
简写格式还能够对输出的变量重命名:学习
// 再次修改math.js var PI = 3.14; var add = function (x, y) { return x + y; } export { PI, add as Add}; // 把输出变量add重命名为Add(注意不用双引号)
经过关键字as
把输出变量add
重命名为Add
(Add是个字面量,不是字符串不须要引号)。prototype
一样在index.js模块也要修改下:code
import * as Math from "./math.js"; console.log(Math.PI); console.log(Math.Add(1, 2)); // Add方法名称改动了。
export
语句后面能够跟什么?命名导出须要同时指定导出的变量名称和变量值,因此export
语句后面跟的通常是:
export
简写格式。不能够是表达式,由于表达式只有值,没有名字。
// 语法错误:Declaration or statement expected export 3.14
经过关键字default
修饰export
能够指定一个模块的默认输出变量值(在导入模块的默认输出时,不须要指定导出变量名称,这个后面再说)。
// Case 3 常量 export default 25; // Case 4 变量 var PI = 3.14; export default PI // Case 5 函数 export default function add2( x, y) { return x + y; }
default
的模块输出变量;export default 3.14
export
命名导出;export default
默认导出;export
语句必须在模块做用域的最顶层,即export
不能够出如今任意花括号内,如函数语句里,子代码块里(控制语句)。经过import
语句导入外部模块。对应export
语句的两种导出方式,import
也分别存在两种不一样的模块导入语法格式。
修改index.js:
import { PI, Add } from './math.js'; console.log(PI); console.log(Add(1, 2));
表示:导入math.js模块里输出的变量PI
, Add
。
注意名称必需要和math.js模块的输出变量一一对应,不然就是undefined
。
该格式还支持对导入的变量重命名:
import { PI as pi, Add as add} from './math.js';
*
若是导入一个模块全部命名输出,可采用通配符*
。
// 修改index.js import * as Math from './math.js'; // 此时必须经过as指定个别名 console.log(Math.PI); console.log(Math.Add(1, 2));
表示导入模块math.js全部命名输出变量,并经过Math
变量访问全部命名导出的变量。Math
变量是个特殊的对象,叫模块对象。
Object.prototype.toString.call(Math); // [object Module]
而且这个对象和它的属性都是只读的(后面细说)。
// 修改math.js: var PI = 3.14; var add = function (x, y) { return x + y; } export { PI, add as Add }; // 简写格式,统一列出须要输出的变量 export default function say() { // 默认输出 console.log("I am default export"); }
修改index.js:
import say from "./math.js"; say();
as
重命名;导入模块默认输出的名字能够任意命名。
import say2 from "./math.js"; // say2();
import say, * as Math from './math.js'; // OR import say, { PI, Add } from './math.js';
默认导入必定放在命名导入前面
// 非法 import * as Math, say from './math.js'; // 非法 import { PI, Add }, say from './math.js';
若是只导入一个模块,但不引用模块的输出变量,能够简写为:
import './math.js'
此时只会触发模块math.js的执行。
import xx from "xxx"
导入默认输出;import { xx } from "xxx"
导入指定的命名输出;import * as xx from "xxx"
导入所有命名输出;import "xxx"
只导入;import
语句也必须在模块的最顶层做用域里,即import不能够出如今任意花括号内,如函数语句里,子代码块里(控制语句)。模块能够导出任何类型变量(引用变量和值变量),若是在模块index.js里修改了模块math.js导出的引用变量或者值变量,那会影响模块math.js里的值么?
很遗憾,import
导入的变量和变量的属性都是只读的,不能也不该该修改引入的变量值。
import * as Math from './math.js'; // TypeError: Cannot assign to read only property 'Count' of object '[object Module]' Math.Count = 12;
反过来想一想,若是模块math.js修改了其导出的引用变量或者值变量在,那会影响模块index.js里的取值么?
修改math.js:
var Count = 0; var increase = function() { Count++; } var Person = { name: 'Bob' } var changeName = function() { Person.name = 'John'; } export { Count, Person, increase, changeName };
修改index.js:
import * as Math from './math.js'; console.log(`Person:${JSON.stringify(Math.Person)}, Count:${Math.Count}`);// 修改前 Math.increase(); Math.changeName(); console.log(`Person:${JSON.stringify(Math.Person)}, Count:${Math.Count}`);// 修改后
输出:
Person:{"name":"Bob"}, Count:0
Person:{"name":"John"}, Count:1
从输出能够看出只要math.js修改了导出值就会影响index.js的取值。
The static import statement is used to import read only live bindings which are exported by another module
export
语句了解了export
和import
基本用法后,咱们再看看export
语句另外一个语法规则:导出引入的模块的变量。
上面的例子里export
语句都是导出模块自身定义的变量,其实export
还能够导出模块引入模块的输出。
在目录添加文件log.js:
export var Log = function(msg) { console.log(msg); } export default 'I am log.js';
修改math.js:
var Count = 0; var increase = function() { Count++; } var Person = { name: 'Bob' } var changeName = function() { Person.name = 'John'; } export { Count, Person, increase, changeName}; export default function say() { console.log(`Person:${JSON.stringify(Person)}, Count:${Count}`) } export * from './log.js'; //
修改index.js:
import say, * as Math from './math.js'; Math.Log('hello'); // 该方法来之log.js模块
查看下输出是否OK。
其中export * from './log.js';
表示导出模块log.js全部的命名输出。等价于:
export { Log } from './log.js';
注意: 这种语法格式export * from './log.js';
不能够定义别名,而花括号的语法格式export { Log } from './log.js'
能够定义别名,即:
export { Log as log} from './log.js'
怎么在math.js模块里导出模块log.js的默认输出呢?
只能采用先导入,再导出方式:
import logName from './log.js'; export { logName }
整理自gitHub笔记ES2015模块 & import, export