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';
上面的總結,更加清晰明瞭,細節上還有很多地方需要注意,建議多敲代碼,明天再更、、、