前言:es6
这是阮一峰老师的ECMA6入门module一章的缩减,只抽取了我在项目中有用到的内容。带着问题去看老师的教程。感受吸取更快,也明白了偶尔遇到的export不出来的问题。浏览器
es6模块设计思想:服务器
ES6 模块的设计思想,是尽可能的静态化,使得编译时就能肯定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时肯定这些东西。好比,CommonJS 模块就是对象,输入时必须查找对象属性。app
es6模块不是对象:函数
// CommonJS模块 let { stat, exists, readFile } = require('fs'); // 等同于 let _fs = require('fs'); let stat = _fs.stat, exists = _fs.exists, readfile = _fs.readfile;
上面代码的实质是总体加载fs
模块(即加载fs
的全部方法),生成一个对象(_fs
),而后再从这个对象上面读取3个方法。这种加载称为“运行时加载”,由于只有运行时才能获得这个对象,致使彻底没办法在编译时作“静态优化”。工具
ES6 模块不是对象,而是经过export
命令显式指定输出的代码,再经过import
命令输入。不会加载整个fs。优化
// ES6模块 import { stat, exists, readFile } from 'fs';
因为 ES6 模块是编译时加载,使得静态分析成为可能。ui
除了静态加载带来的各类好处,ES6 模块还有如下好处。spa
UMD
模块格式了,未来服务器和浏览器都会支持 ES6 模块格式。目前,经过各类工具库,其实已经作到了这一点。navigator
对象的属性。Math
对象),将来这些功能能够经过模块提供。关于es6模块的特性设计
1、严格模式:
es6模块默认使用严格模式,无论你有没有使用 'use strict'
2、export
模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其余模块提供的功能。
须要特别注意的是,export
命令规定的是对外的接口,必须与模块内部的变量创建一 一对应关系。
这里的意思是不能直接输入一个变量,函数,类
// 报错 export 1; // 报错 var m = 1; export m;
正确的,有一一对应关系的export,函数 function,类 class 也是要遵照这种规则的。
// 写法一:这种我不理解 export var m = 1; // 写法二:输出一个对象,这个对象有一个 m 属性,m属性与m变量,一一对应 var m = 1; export {m}; // 写法三:输出一个n,n与m一一对应 var n = 1; export {n as m};
// 报错:输出的 f 就是 函数 f 没有对应关系 function f() {} export f; // 正确 export function f() {}; // 正确 function f() {} export {f};
export的换名输出
function v1() { ... } function v2() { ... } export { v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion };
3、import
使用export
命令定义了模块的对外接口之后,其余 JS 文件就能够经过import
命令加载这个模块。
注意:import在编译阶段执行,能够理解为跟变量提高,函数提高有同样的特性,可是比这两种提高晚一点执行。
foo(); import { foo } from 'my_module';
上面的代码不会报错,由于import
的执行早于foo
的调用。这种行为的本质是,import
命令是编译阶段执行的,在代码运行以前。
import
语句会执行所加载的模块,所以能够有下面的写法。只执行一下lodash,可是不输入任何值
import 'lodash';
只想列出不一样的import写法:
// 变量名与export一一对应 import {firstName, lastName, year} from './profile'; // 使用新变量名代替 import { lastName as surname } from './profile';
4、模块的总体加载
一个模块中能够有多个export,import中可使用 * 把他们所有收在一个对象中 * as mymodule
import * as circle from './circle';
5、export default 命令
为模块设置默认输出,在import的时候不须要使用{},也能够随便给一个名字这个默认输出。
// export-default.js export default function foo() { console.log('foo'); } // 或者写成 function foo() { console.log('foo'); } export default foo; // import import xxx from 'export-default.js'
本质上,export default
就是输出一个叫作default
的变量或方法,而后系统容许你为它取任意名字。
// modules.js function add(x, y) { return x * y; } export {add as default}; // 等同于 // export default add; // app.js import { default as xxx } from 'modules'; // 等同于 // import xxx from 'modules';
正是由于export
default
命令其实只是输出一个叫作default
的变量,因此它后面不能跟变量声明语句。(怪不得总是说,找不到模块)
// 正确 export var a = 1; // 正确 var a = 1; export default a; // 错误 export default var a = 1;
同时想要两种输出
import _, { each } from 'lodash';
8、es6模块加载的实质
ES6模块加载的机制,与CommonJS模块彻底不一样。CommonJS模块输出的是一个值的拷贝(值类型是拷贝,引用类型是引用),而ES6模块输出的是值的引用(值类型,引用类型都是引用)。
问题1:
commonJS 获得的是一个复制,require后获得的mod.counter,跟lib.js里面的counter已经没有联系,(能够理解为require多少次,复制多少份)
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, }; // main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3
es6模块的优势就是共享一份,由于它输出的仅仅是引用
// lib.js export let counter = 3; export function incCounter() { counter++; } // main.js import { counter, incCounter } from './lib'; console.log(counter); // 3 incCounter(); console.log(counter); // 4