require 屬於 commonJS 規範,想了解詳細的,戳我;javascript
靜態 import,動態 import() 屬於 ES6 規範;html
require 能夠引用 JS、json 等;
// test.js module.exports = { a: "china", b: function() { console.log("b"); } }; //引用 var test = require("./test"); test.b();
export 能夠處處變量、對象、函數、類等
寫法 1:export + 完整定義變量或者函數的表達式vue
// 變量 export var a = 10; // 函數 export function name() {} // 這種寫法要求,必需要是完整定義;好比,變量要有 var、const、let字段,函數要有 function字段
錯誤寫法:java
// 變量 表達式不完整 var a=10; export a; // 函數 表達式不完整 var name=function(){}; export name; // 對象 export { a:"name" } // 常量 export 1;
驗證網址,戳我,能夠驗證上述 是否正確;node
寫法 2:export {變量名}
針對方法 1 中的錯誤寫法,能夠以下改正:jquery
// 變量名加花括號 var a = 10; export { a }; // 函數名加花括號 var name = function() {}; export { name }; // 多個變量時 export { a, name }; // 通常JS文件,好比utils 文件,在每一個方法或者變量前加export,而不是 export {a,name}這種形式;這樣寫的好處,比較方便移植; export function name() {} export var a = "test";
寫法 3:export default
語法糖es6
使用export default
寫法,爲模塊指定默認輸出,這樣就不須要知道所要加載模塊的變量名;export default
在一個 JS 文件中只能使用一次;
// 變量 var a = 10; export default a; // 函數 export default function() {} // 等效於 function fun() {} export { fun as default }; // 導出default變量以及其餘變量 export { fun as default, a, name }; // 針對 export { fun as default, a, name };在utils文件中還能夠 export default fun; export var a = 0; export var name = "china";
as
關鍵字用來取別名;加入引入多個文件,有相同的變量名,可使用使用as
關鍵字避免衝突
// a.js var a = function() {}; export { a as fun }; // b.js import { fun as a } from "./a"; a();
引入文件不含有export default
json
import { a, b, c } from "./a";
引入文件僅含有 export default
segmentfault
import a from "./d"; //等效於 import { default as a } from "./d";
引入文件既含有export default
,還含有其餘export
設計模式
import $, { each, map } from "jquery";
import 命令會被 JS 引擎靜態分析(編譯階段),先於其餘模塊執行;
// 報錯 if (x > 2) { import a from "./a"; } ///repl: 'import' and 'export' may only appear at the top level (2:2)
上面代碼中,引擎處理 import 語句是在編譯時,這時不會去分析或執行 if 語句,因此 import 語句放在 if 代碼塊之中毫無心義,所以會報句法錯誤,而不是執行時錯誤。也就是說,import 和 export 命令只能在模塊的頂層,不能在代碼塊之中(好比,在 if 代碼塊之中,或在函數之中)。
這樣的設計,當然有利於編譯器提升效率,但也致使沒法在運行時加載模塊。在語法上,條件加載就不可能實現。若是 import 命令要取代 Node 的 require 方法,這就造成了一個障礙。由於 require 是運行時加載模塊,import 命令沒法取代 require 的動態加載功能。
特色 1:import() 返回 promise 對象
特色 2:相較於 import 命令,import()能夠實現動態加載,其路徑能夠根據狀況改變
特色 3:import()適用在運行階段,而不是像 import 同樣在編譯階段,這意味着 import(),可使用在 JS 代碼中,好比條件判斷,函數中等
場景 1:按需加載
import()能夠在須要的時候,再加載某個模塊。vue 中異步組件的使用,也用到了 import()方法;戳這裏
場景 2:條件加載
import()能夠放在 if 代碼塊,根據不一樣的狀況,加載不一樣的模塊。
if (condition) { import('moduleA').then(...); } else { import('moduleB').then(...); }
場景 3:動態的模塊路徑
import()容許模塊路徑動態生成。
import(f()).then(...);
注意點:
import()加載模塊成功之後,這個模塊會做爲一個對象,看成 then 方法的參數。所以,可使用對象解構賦值的語法,獲取輸出接口。
import("./myModule.js").then(({ export1, export2 }) => { // ...· });
上面代碼中,export1 和 export2 都是 myModule.js 的輸出接口,能夠解構得到。
若是模塊有 default 輸出接口,能夠用參數直接得到。
import("./myModule.js").then(myModule => { console.log(myModule.default); });
上面的代碼也可使用具名輸入的形式。
import("./myModule.js").then(({ default: theDefault }) => { console.log(theDefault); });
若是想同時加載多個模塊,能夠採用下面的寫法。
Promise.all([ import('./module1.js'), import('./module2.js'), import('./module3.js'), ]) .then(([module1, module2, module3]) => { ··· });
import()也能夠用在 async 函數之中。
async function main() { const myModule = await import("./myModule.js"); const { export1, export2 } = await import("./myModule.js"); const [module1, module2, module3] = await Promise.all([ import("./module1.js"), import("./module2.js"), import("./module3.js") ]); } main();
module.exports 有兩種寫法:
針對上述結論以及 module.exports 兩種寫法,做了以下測試:
// requie.js module.exports從新賦值 日期 console.log("I am require.js"); module.exports = new Date(); // index.js const t = require("./require.js"); console.log(t.getTime()); setTimeout(() => { const t = require("./require.js"); console.log(t.getTime()); }, 3000); console.log("執行頁面"); // 結果: // I am require.js // 1576220112564 // 執行頁面 // 1576220112564
// require.js module.exports從新賦值 對象;日期做爲對象屬性值 module.exports = { t: new Date() }; // index.js const { t } = require("./require.js"); console.log(t.getTime()); setTimeout(() => { const { t } = require("./require.js"); console.log(t.getTime()); }, 3000); console.log("執行頁面"); // 結果: // 1576219864761 // 1576219864761
// require.js module.exports從新賦值 對象;日期賦值給變量,做爲函數導出值 let t = new Date(); module.exports = { get: () => { return t; } }; // index.js const { get } = require("./require.js"); console.log(get().getTime()); setTimeout(() => { const { get } = require("./require.js"); console.log(get().getTime()); }, 3000); // 結果: // 1576219588328 // 1576219588328
// require.js module.exports做爲對象,日期賦值給t屬性 module.exports.t = new Date(); // index.js const foo = require("./require.js"); console.log(foo.t.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.getTime()); }, 3000); // 結果: // 1576228870548 // 1576228870548
// require.js module.exports做爲對象;日期做爲對象的值 module.exports.t = { time: new Date() }; // index.js const foo = require("./require.js"); console.log(foo.t.time.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.time.getTime()); }, 3000); // 結果: // 1576229080434 // 1576229080434
// require.js 從新賦值對象;日期在函數中運行(暴露函數) module.exports = { get: () => { return new Date(); } }; // index.js const { get } = require("./require.js"); console.log(get().getTime()); setTimeout(() => { const { get } = require("./require.js"); console.log(get().getTime()); }, 3000); // 結果: // 1576219323353 // 1576219326358
結論:上述狀況總結下,require 要想不受緩存影響,把變量等定義在函數中,利用函數延遲執行的特色來解決;
--------兩次導出 module.exports------------
// require.js module.exports.t = new Date(); setTimeout(() => { module.exports.t = new Date(); }, 500); // index.js const foo = require("./require.js"); console.log(foo.t.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.getTime()); }, 3000); // 結果: // 1576225753706 // 1576225754208
// require.js module.exports = new Date(); setTimeout(() => { module.exports = new Date(); }, 500); // index.js const foo = require("./require.js"); console.log(foo.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.getTime()); }, 3000); // 結果: // 1576226052279 // 1576226052781
// require.js module.exports = { t: new Date() }; setTimeout(() => { module.exports = { t: new Date() }; }, 500); // index.js const foo = require("./require.js"); console.log(foo.t.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.getTime()); }, 3000); // 結果: // 1576227838138 // 1576227838639
結論,只要是這種 module.exports 導出兩次的,都不會有緩存;
針對上述結論,做了以下測試:
// import.js console.log("import 執行"); export default new Date();
<script type="module"> import a from "./import/import.js"; import z from "./import/import.js"; console.log(a.getTime()); console.log(z.getTime()); // 結果: // import 執行 // 1576478875409 // 1576478875409 </script>
console.log("import 執行"); export default new Date();
<script type="module"> var b = import("./import/import.js"); b.then(({ default: time }) => { console.log(time.getTime()); }); setTimeout(() => { var c = import("./import/import.js"); c.then(({ default: time }) => { console.log(time.getTime()); }); }, 3000); // 結果: // 調用文件執行 // import 執行 // 1576479834365 // 1576479834365 </script>
// require.js console.log("I am require.js"); module.exports.t = { time: new Date() }; // index.js const foo = require("./require.js"); console.log(foo.t.time.getTime()); setTimeout(() => { const foo = require("./require.js"); console.log(foo.t.time.getTime()); }, 3000); console.log("執行頁面"); // 結果: // I am require.js // 1576483718781 // 執行頁面 // 1576483718781
console.log("import 執行"); export default new Date();
<script type="module"> var b = import("./import/import.js"); b.then(({ default: time }) => { console.log(time.getTime()); }); setTimeout(() => { var c = import("./import/import.js"); c.then(({ default: time }) => { console.log(time.getTime()); }); }, 3000); // 結果: // 調用文件執行 // import 執行 // 1576479834365 // 1576479834365 </script>
本身總結這篇的時候,查了很多資料,本身作了一些測試,儘可能保證所寫的結論,可以獲得實踐的支撐,以避免貽誤他人;若是文中,有哪些代碼問題,或者邏輯錯誤,歡迎指正!
本人在平常學習中,也收集了一些有價值的資料,涉及到諸如源碼、設計模式等,歡迎一塊兒交流學習!
es6 import()函數
require、緩存
export MDN
NodeJS 中的 require 和 import
require,import 和 import()函數的區別
require 和 import 的區別是什麼?看這個你就懂了
模塊化
深刻理解 ES6 模塊機制
萬歲,瀏覽器原生支持 ES6 export 和 import 模塊啦!