ES6模块加载export 、import、export default 、import() 语法与区别
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。
CommonJS 用于服务器,AMD 用于浏览器。
ES6 在语言标准层面上,实现了模块功能,而且简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
严格模式主要有以下限制。
变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀 0 表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用fn.caller和fn.arguments获取函数调用的堆栈
增加了保留字(比如protected、static和interface)
上面这些限制,模块都必须遵守。由于严格模式是 ES5 引入的,不属于 ES6,所以请参阅相关 ES5 书籍。
其中,尤其需要注意this的限制。ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this。
//index.js
//export 命令
var a = 'a';
var b = 'b';
var c = 'c';
//命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。用大括号
export {
a,b,c
}
export var d = 'd';
export {d}
export function f(){}
export {f}
//报错
export 1;
// 报错
var m = 1;
export m;
// 报错
function f() {}
export f;
--------------------------------------------------------------------------------------------
//export重命名语句 原命名 as 新命名
export {
a as m,
b as n
}
--------------------------------------------------------------------------------------------
//export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
//输出变量foo,值为bar,500 毫秒之后变成baz。
//这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);
--------------------------------------------------------------------------------------------
//export命令可以在模块的任何位置,必须处于模块顶层,如果在块级作用域没法静态化会报错。
//报错
function foo() {
export default 'bar'
}
foo()
//main.js
//import命令
import {a} from 'index.js';
import {b} from 'index.js';
import {c} from 'index.js';
//等同于
import {a,b,c} from 'index';//以上两种写法相同,import语句是独生模式
--------------------------------------------------------------------------------------------
import {a} from 'index';
//报错 变量a是只读的,可以改写a的属性
var a = '1';
//合法操作,但是其他模块输入读到改写后的值,不推荐使用难以查错,可用于特殊场景路由控制等等
var a.foo = 'ok';
--------------------------------------------------------------------------------------------
//import 有提升效果,会提升到模块头部执行
foo();
import { foo } from 'my_module';//ok
--------------------------------------------------------------------------------------------
//import 是静态执行,不可以用变量和表达式,不能使用这些只有在运行时才能得到结果的语法结构。
// 报错
import { 'f' + 'oo' } from 'my_module';
// 报错
let module = 'my_module';
import { foo } from module;
// 报错
if (x === 1) {
import { foo } from 'module1';
} else {
import { foo } from 'module2';
}
//模块使用整体加载
//circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
//index.js
//逐一加载下面写法
import { area, circumference } from './circle';
console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));
//使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。
import * as circle from './circle';
console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));
//export default 命令
//方便加载,import命令可以为该匿名函数指定任意名字。
// export-default.js
export default function () {
console.log('foo');
}
// import-default.js
import customer from './export-default';
customer(); // 'foo'
--------------------------------------------------------------------------------------------
//对应的import语句不需要使用大括号
import customName from './index';
customName(); // 'foo'
//两种写法
export default function () {
console.log('foo');
}
//或者写成
function foo() {
console.log('foo');
}
export default foo;
--------------------------------------------------------------------------------------------
//export default 就是输出一个叫做default的变量或方法
// 正确
export var a = 1;
// 正确
var a = 1;
export default a;
// 错误
export default var a = 1;
//export default命令输出变量时,本质是将后面值,赋给default变量,所以可以直接将一个值写在export default之后
// 正确
export default 42;
// 报错
export 42;
--------------------------------------------------------------------------------------------
//export default 允许用 as 任意命名,重命名为 default 有效
function add(x, y) {
return x * y;
}
export {add as default};
// 等同于
export default add;
//main.js 引用
import { default as add } from './index';
//等同于
import add from './index';
--------------------------------------------------------------------------------------------
//有了export default命令,import 可以同时输入默认方法和其他接口
//moudle.js
export default function (obj) {
}
export function each(obj, iterator, context) {
}
export { each as forEach };
//index.js
import a, { each, forEach } form 'moudle';
--------------------------------------------------------------------------------------------
//export default也可以用来输出类
// MyClass.js
export default class {
}
// main.js
import MyClass from 'MyClass';
let o = new MyClass();
//import 和 export 复合写法
//export和import语句可以结合写成一行。相当于对外转发了接口,导致当前模块不能直接使用foo和bar。
export { foo, bar } from 'my_module';
// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };
--------------------------------------------------------------------------------------------
//模块的接口改名和整体输出,也可以采用这种写法。
// 接口改名
export { foo as myFoo } from 'my_module';
// 整体输出
export * from 'my_module';
--------------------------------------------------------------------------------------------
//默认接口的写法如下。
export { default } from 'foo';
--------------------------------------------------------------------------------------------
//具名接口改为默认接口的写法如下。
export { es6 as default } from './someModule';
// 等同于
import { es6 } from './someModule';
export default es6;
--------------------------------------------------------------------------------------------
//默认接口也可以改名为具名接口。
export { default as es6 } from './someModule';
--------------------------------------------------------------------------------------------
//注意下面三种import语句,没有对应的复合写法。为了做到形式的对称,现在有提案。
import * as someIdentifier from "someModule";//*号重命名整体加载
import someIdentifier from "someModule";//默认接口重命名
import someIdentifier, { namedIdentifier } from "someModule";//同时输入默认方法和其他接口
//模块继承
//circleplus模块 继承 circle模块。
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
export default function(){
}
// circleplus.js
//这里是复合写法,export *,表示再输出circle模块所有属性和方法。注意,export *命令会忽略circle模块的default方法。然后,上面代码又输出了自定义的e变量和默认方法。
export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
//也可以将circle的属性或方法,改名后再输出。将其改名为circleArea。
// circleplus.js
export { area as circleArea } from 'circle';
//加载模块 import exp表示,将circleplus模块的默认方法加载为exp方法。
// main.js
import * as math from 'circleplus';
import exp from 'circleplus';
console.log(exp(math.e));
//跨模块常量
//const声明的常量只在当前代码块有效。建一个专门的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/index';
上面的总结,更加清晰明了,细节上还有很多地方需要注意,建议多敲代码,明天再更、、、