Js模塊化導入導出
CommonJs
、AMD
、CMD
、ES6
都是用於模塊化定義中使用的規范,其為了規范化模塊的引入與處理模塊之間的依賴關系以及解決命名沖突問題,並使用模塊化方案來使復雜系統分解為代碼結構更合理,可維護性更高的可管理的模塊。
CommonJS
CommonJS
是NodeJs
服務器端模塊的規范,根據這個規范,每個文件就是一個模塊,有自己的作用域。在一個文件里面定義的變量、函數、類,都是私有的,對其他文件不可見。CommonJS
規范規定,每個模塊內部,module
變量代表當前模塊。這個變量是一個對象,它的exports
屬性是對外的接口。加載某個模塊,其實是加載該模塊exports
屬性。總之,CommonJS
規范通過require
導入,module.exports
與exports
進行導出。
// 1.js
var a = 1;
var b = function(){
console.log(a);
}
module.exports = {
a: a,
b: b
}
/*
// 當導出的模塊名與被導出的成員或方法重名時可以有如下寫法
module.exports = {
a,
b
}
*/
// 2.js
var m1 = require("./1.js")
console.log(m1.a); // 1
m1.b(); // 1
也可以使用exports
進行導出,但一定不要重寫exports
的指向,因為exports
只是一個指針並指向module.exports
的內存區域,即exports = module.exports = {}
,重寫exports
則改變了指針指向將導致模塊不能導出,簡單來說exports
就是為寫法提供了一個簡便方案,最后其實都是利用module.exports
導出。此外若是在一個文件中同時使用module.exports
與exports
,則只會導出module.exports
的內容
// 1.js
var a = 1;
var b = function(){
console.log(a);
}
exports.a = a;
exports.b = b;
// exports = { a, b } // 不能這么寫,這樣就改變了exports的指向為一個新對象而不是module.exports
// 2.js
var m1 = require("./1.js")
console.log(m1.a); // 1
m1.b(); // 1
AMD
AMD
規范不是AMD YES
,AMD
異步模塊定義,全稱Asynchronous Module Definition
規范,是瀏覽器端的模塊化解決方案,CommonJS
規范引入模塊是同步加載的,這對服務端不是問題,因為其模塊都存儲在硬盤上,可以等待同步加載完成,但在瀏覽器中模塊是通過網絡加載的,若是同步阻塞等待模塊加載完成,則可能會出現瀏覽器頁面假死的情況,AMD
采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成之后,這個回調函數才會運行,RequireJS
就是實現了AMD
規范。
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// do something
});
define(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// do something
return {};
});
/**
define和require在依賴處理和回調執行上都是一樣的,不一樣的地方是define的回調函數需要有return語句返回模塊對象(注意是對象),這樣define定義的模塊才能被其他模塊引用;require的回調函數不需要return語句,無法被別的模塊引用
*/
// html的<script>標簽也支持異步加載
// <script src="require.js" defer async="true" ></script> <!-- async屬性表明這個文件需要異步加載,避免網頁失去響應。IE不支持這個屬性,只支持defer,所以把defer也寫上。 -->
CMD
CMD
通用模塊定義,是SeaJS
在推廣過程中對模塊定義的規范化產出,也是瀏覽器端的模塊化異步解決方案,CMD
和AMD
的區別主要在於:
- 對於依賴的模塊,
AMD
是提前執行(相對定義的回調函數,AMD
加載器是提前將所有依賴加載並調用執行后再執行回調函數),CMD
是延遲執行(相對定義的回調函數,CMD
加載器是將所有依賴加載后執行回調函數,當執行到需要依賴模塊的時候再執行調用加載的依賴項並返回到回調函數中),不過RequireJS
從2.0
開始,也改成可以延遲執行 AMD
是依賴前置(在定義模塊的時候就要聲明其依賴的模塊),CMD
是依賴就近(只有在用到某個模塊的時候再去require
——按需加載,即用即返)。
define(function(require,exports,module){
var a = reuire('require.js');
a.dosomething();
return {};
});
ES6
ES6
在語言標准的層面上實現了模塊的功能,是為了成為瀏覽器和服務器通用的模塊解決方案,ES6
標准使用export
與export default
來導出模塊,使用import
導入模塊。此外在瀏覽器環境中是可以使用require
來導入export
、export default
導出的模塊的,但依然建議使用import
標准導入模塊。
export
、export default
主要有以下區別:
export
能按需導入,export default
不行。export
可以有多個,export default
僅有一個。export
能直接導出變量表達式,export default
不行。export
方式導出,在導入時要加{}
,export default
則不需要。
// 導出單個特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}
// 導出列表
export { name1, name2, …, nameN };
// 重命名導出
export { variable1 as name1, variable2 as name2, …, nameN };
// 解構導出並重命名
export const { name1, name2: bar } = o;
// 默認導出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
// 導出模塊合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
// name-從將要導入模塊中收到的導出值的名稱
// member, memberN-從導出模塊,導入指定名稱的多個成員
// defaultMember-從導出模塊,導入默認導出成員
// alias, aliasN-別名,對指定導入成員進行的重命名
// module-name-要導入的模塊。是一個文件名
// as-重命名導入成員名稱(“標識符”)
// from-從已經存在的模塊、腳本文件等導入
import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name"; // 將運行模塊中的全局代碼, 但實際上不導入任何值。
// 1.js
var a = 1;
var b = function(){
console.log(a);
}
var c = 3;
var d = a + c;
var obj = { a,b,c }
export {a,b};
export {c,d};
export default obj;
<!-- 3.html 由於瀏覽器限制,需要啟動一個server服務 -->
<!DOCTYPE html>
<html>
<head>
<title>ES6</title>
</head>
<body>
</body>
<script type="module">
import {a,b} from "./1.js"; // 導入export
import m1 from "./1.js"; // 不加{}即導入export default
import {c} from "./1.js"; // 導入export 按需導入
console.log(a); // 1
console.log(b); // ƒ (){ console.log(a); }
console.log(m1); // {a: 1, c: 3, b: ƒ}
console.log(c); // 3
</script>
</html>
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://segmentfault.com/a/1190000010426778
https://www.cnblogs.com/leftJS/p/11073481.html
https://www.cnblogs.com/zhoulujun/p/9415407.html
https://www.cnblogs.com/zhoulujun/p/9415407.html
https://www.cnblogs.com/moxiaowohuwei/p/8692359.html