// CommonJS模块引入模块
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
readfile = _fs.readfile;
这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
// ES6模块
import { stat, exists, readFile } from 'fs';
面代码的实质是从fs模块加载3个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。
多的不多说就说一些基本用法个人粗劣的大白话
improt 就是简单的引入模块配合export使用 export是暴露
建一个文件
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
通过export来暴露变量方法 也可以使用export{}
如果不用{} 但是不能直接使用实际的常量值
引用加载
// main.js
import { area, circumference } from './circle';
console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));
使用import{}form+"路径"来引用
加载所有暴露的变量方法
import * as circle from './circle';
console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));
*代表所有 as 可以自定义一个变量名字
exprot default
从前面的例子可以看出,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法
export default为模块指定默认输出。
// export-default.js
export default function () {
console.log('foo');
}
上面代码是一个模块文件export-default.js,它的默认输出是一个函数。
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
// import-default.js
import customName from './export-default';
customName(); // 'foo'
export default命令用在非匿名函数前,也是可以的。
// export-default.js
export default function foo() {
console.log('foo');
}
// 或者写成
function foo() {
console.log('foo');
}
export default foo;
上面代码中,foo函数的函数名foo,在模块外部是无效的。加载的时候,视同匿名函数加载。
下面比较一下默认输出和正常输出。
// 第一组
export default function crc32() { // 输出
// ...
}
import crc32 from 'crc32'; // 输入
// 第二组
export function crc32() { // 输出
// ...
};
import {crc32} from 'crc32'; // 输入
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。所以,下面的写法是有效的。只不过省略了default而已
// modules.js
function add(x, y) {
return x * y;
}
export {add as default};//输出default
// 等同于
// export default add;
// app.js
import { default as xxx } from 'modules';
// 等同于
// import xxx from 'modules';
输出所有
export * from 'circle';
输出暴露 'circle';的所有属性方法
引入所有的
import * as math from 'circleplus';
引入 'circleplus'';的所有属性方法
跨模块常量
一个值要被多个模块共享
// constants.js 模块
export const A = 1;export const B = 3;export const C = 4;
//test1.js 模块
import * as constants from './constants';console.log(constants.A);
// 1console.log(constants.B); // 3
// test2.js 模块
import {A, B} from './constants';console.log(A); // 1console.log(B); // 3
如果要使用的常量非常多,可以建一个专门的constants
目录,将各种常量写在不同的文件里面,保存在该目录下。
// constants/db.js
export const db = {
url: 'http://my.couchdbserver.local:5984',
admin_username: 'admin',
admin_password: 'admin password
'};
// constants/user.js
export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];
然后,将这些文件输出的常量,合并在index.js里面。
// constants/index.js
export {db} from './db';export {users} from './users';
使用的时候,直接加载index.js就可以了。
// script.js
import {db, users} from './constants';
inmprot()方法
inport命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适)。所以,下面的代码会报错。
// 报错
if (x === 2) {
import MyModual from './myModual';
}
引擎处理import语句是在编译时 import和export命令只能在模块的顶层,不能在代码块之中(比如,在if代码块之中,或在函数之中)。
如果import命令要取代 Node 的require方法,这就形成了一个障碍。因为require是运行时加载模块,import命令无法取代require的动态加载功能。
const path = './' + fileName;
const myModual = require(path);
上面的语句就是动态加载,require到底加载哪一个模块,只有运行时才知道。import语句做不到这一点。
因此,有一个提案,建议引入import()函数,完成动态加载。
import(specifier)
上面代码中,import函数的参数specifier,指定所要加载的模块的位置。import命令能够接受什么参数,import()函数就能接受什么参数,两者区别主要是后者为动态加载。import() 返回一个 Promise 对象。
js的异步加载
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
es6
<script src="...js" type="module"></script>
自动异步 也可以设置async同步
——————————
ES6 模块与 CommonJS 模块的差异
讨论 Node 加载 ES6 模块之前,必须了解 ES6 模块与 CommonJS 模块完全不同。
它们有两个重大差异。
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
ES6模块的转码
浏览器目前还不支持ES6模块,为了现在就能使用,可以将转为ES5的写法。除了Babel可以用来转码之外,还有以下两个方法,也可以用来转码。
1:ES6 module transpiler
ES6 module transpiler是 square 公司开源的一个转码器,可以将 ES6 模块转为 CommonJS 模块或 AMD 模块的写法,从而在浏览器中使用。
首先,安装这个转码器。
$ npm install -g es6-module-transpiler
然后,使用compile-modules convert 命令,将 ES6 模块文件转码。
$ compile-modules convert file1.js file2.js
参数可以指定转码后的文件名。
$ compile-modules convert -o out.js file1.js
————————————————————————————
SystemJS
另一种解决方法是使用 SystemJS。它是一个垫片库(polyfill),
可以在浏览器内加载 ES6 模块、AMD 模块和 CommonJS 模块,
将其转为 ES5 格式。它在后台调用的是 Google 的 Traceur 转码器。
--
使用时,
先在网页内载入system.js文件。
<script src="system.js"></script>
然后,使用System.import方法加载模块文件。
<script> System.import('./app.js');</script>
--
上面代码中的./app
,指的是当前目录下的app.js文件。它可以是ES6模块文件,System.import
会自动将其转码
----。
需要注意的是,System.import使用异步加载,返回一个 Promise 对象,可以针对这个对象编程。下面是一个模块文件。
// app/es6-file.js:export class q { constructor() { this.es6 = 'hello'; }}
然后,在网页内加载这个模块文件。
<script>System.import('app/es6-file').then(function(m) { console.log(new m.q().es6); // hello});</script>
--
上面代码中,System.import
方法返回的是一个 Promise 对象,所以可以用then
方法指定回调函数。