import和export的使用

最近发现自己基础知识还差的远,很多东西知其然不知其所以然。现在很多项目都可以借助现成的工具来实现,所以真的是越来越少关注了。
但是,基础知识是一个工程师的必备素养,也是你提高的基石,所以我就从一些简单的问题开始做一个系列的记录吧。现在从模块化编程开始吧。

以前:

CommonJS(服务器) 和 AMD(浏览器)规范各自实现了运行时加载模块的方法(没办法在编译时做“静态优化”)。

// CommonJS模块
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

现在:

ES6:一个模块就是一个文件,export/import命令可以出现在模块的任何位置,只要处于模块顶层就可以。
通过import和export实现静态加载(编译时加载),服务端和浏览器通用。

// ES6模块
import { stat, exists, readFile } from 'fs';

export:如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};

还可以输出函数和class类:

export function multiply(x, y) {
return x * y;
};

还可以改个名字输出:

function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};

需要特别注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
CommonJS 模块输出的是值的缓存,不存在动态更新。

import:加载模块

// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}

可以改名字:

import { lastName as surname } from './profile';

注意,import命令具有提升效果,会提升到整个模块的头部,首先执行。import命令是编译阶段执行的,在代码运行之前。
由于import是静态执行,所以不能使用表达式和变量。

会执行加载的模块:

import 'lodash';//仅仅执行lodash模块,但是不输入任何值。多次引入同一个模块仅执行一次。

整体加载所有的模块:

import * as circle from './circle';

export default:为模块指定默认输出,引用的时候不用知道输出的到底是什么,可以指定任意名字。
需要注意的是,这时import命令后面,不使用大括号。一个模块只能有一个默认输出。

// export-default.js
export default function () {
console.log('foo');
}
// import-default.js
import customName from './export-default';
customName(); // 'foo'

同时引用默认模块和其他模块:

//输出
export default function (obj) {
// ···
}
export function each(obj, iterator, context) {
// ···
}
export { each as forEach };
//对应的加载
import _, { each, each as forEach } from 'lodash';

ES6模块加载CommonJS模块:

//commonjs模块:
// a.js
module.exports = {
foo: 'hello',
bar: 'world'
};
// 等同于
export default {
foo: 'hello',
bar: 'world'
};
//es6加载上面的模块:
// 写法一
import baz from './a';
// baz = {foo: 'hello', bar: 'world'};
// 写法二
import {default as baz} from './a';
// baz = {foo: 'hello', bar: 'world'};
// 写法三
import * as baz from './a';
// baz = {
// get default() {return module.exports;},
// get foo() {return this.default.foo}.bind(baz),
// get bar() {return this.default.bar}.bind(baz)
// }

CommonJS加载ES6模块:通过import()函数

// es6.mjs
let foo = { bar: 'my-default' };
export default foo;
foo = null;
// commonjs.js
const es_namespace = await import('./es');
// es_namespace = {
// get default() {
// ...
// }
// }
console.log(es_namespace.default);
// { bar:'my-default' }

参考

感谢阮一峰老师的ES6入门教程