什麼是模組?深刻理解ES6模組
1.模組
1.1 什麼是模組?什麼是模組化?
玩過FPS遊戲的朋友應該知道,一把組裝完整的M4步槍,一般是槍身 消音器 倍鏡 握把 槍托
。
如果把M4步槍看成是一個頁面的話,那麼我們可以做如下類比槍身-> <main></main>
#消音器-> <header></header>
倍鏡-> <nav></nav>
#握把-> <aside></aside>
槍托-> <footer></footer>
#OK,你剛剛做了一件事情,就是把m4步槍拆成了五個部分,你拆分的每一個部分就是一個模組【module】,你拆分的這個過程就是模組化【modularization】。
模組化是一種程式設計思想,其核心就是分割任務,把複雜問題簡單化,這樣一來既方便多人分工協作,又可以幫助我們快速定位問題
方便多人分工協作- 可以不同的人開發不同的模組,再組合,大大增加團隊效率
-
幫助我們快速定位問題- 後座力太大,那八成是槍託或握把的問題;聲音過大,那八成是消音器的問題。
1.2 模組化的血淚史
下面用一個小栗子講一講模組化的發展史
龔先生和棚先生一起接了一個項目,他們兩個需要分別實現一些功能,很簡單,就是Console出來自己的變數a
於是他們倆一合計,安排龔先生的程式碼單獨放在 script1.js
裡寫,棚先生的程式碼單獨放在script2.js
裡寫,然後用script標籤分別引入
// script1.js文件 var a = 1 console.log(a)
// script2.js文件 var a = 2 console.log(a)
<!--HTML文件--> <script src="./script1.js"></script> <script src="./script2.js"></script>
很快他們遇到了第一個問題—— 變數命名衝突
尤其是包含了異步的時候,會出現如下情況
// script1.js文件 var a = 1 setTimeout(()=>{ console.log(a) // 我们想console出来1,却console出了2 },1000)
// script2.js文件 var a = 2 console.log(a)
上面的問題明顯是由於a是一個全域變數導致的,所以解決想法也很明確-造一個局部變數唄
局部變數
ES5時代使用立即執行函數製造局部變數
// script1.js文件 !function(){ var a = 1 setTimeout(()=>{ console.log(a) // 这下是2了 },1000) }() // 下面有5000行代码
// script2.js文件 console.log(2)
ES6時代直接使用區塊層級作用域let
#// script1.js文件 { let a = 1 setTimeout(()=>{ console.log(a) // 这下是2了 },1000) }
// script2.js文件 { let a = 2 console.log(a) }
透過window連接各個模組
後來公司招募了一個前端大佬,說現在只能由他來控制什麼時候console變量,於是他新建了一個control.js
檔案
並透過window物件連接script1.js和scirpt2.js
// script1.js文件 { let a = 1 window.module1 = function() { console.log(a) } }
// script2.js文件 { let a = 2 window.module2 = function() { console.log(a) } }
// control.js文件 setTimeout(()=>{ window.module1() },1000) window.module2()
這個時候,非常重要的一點就是window是一個全域變數並且充當了一個公用倉庫,這個倉庫有兩個關鍵作用,存【導出】
和取【依賴】
// script1.js文件 { let a = 1 // 把这个函数存放进window,就是导出到window window.module1 = function() { console.log(a) } }
// control.js文件 setTimeout(()=>{ // 我们从window里取出module1函数进行调用,就是依赖了script1.js文件 window.module1() },1000) window.module2()
依賴載入的順序
煩人的產品對需求又進行了更改,給了一個name.js文件
// name.js文件 window.names = ['gongxiansheng','pengxiansheng']
要求現在龔先生和棚先生需要Console出自己的名字
這還不簡單?幾秒鐘寫好
// script1.js文件 { window.module1 = function() { console.log(window.names[0]) } }
// script2.js文件 { window.module2 = function() { console.log(window.names[1]) } }
// control.js文件 setTimeout(()=>{ window.module1() },1000) window.module2()
<!--HTML文件--> <script src="./script1.js"></script> <script src="./script2.js"></script>
但很快他們發現,console出來的都是undefined
前端大佬一眼看出了問題,對他們倆說你們所依賴的程式碼一定要在你們自己的程式碼前引入,不然是取不到值的;你看我的control.js是不是在你們兩個的程式碼後面引入的,因為我用到了你們兩個的程式碼了呀
噢噢,原來是js檔案載入順序問題,改一下吧
<!--HTML文件--> <script src="./name.js"></script> <script src="./script1.js"></script> <script src="./script2.js"></script> <script src="./control.js"></script>
但是在人多了以後,我們到時候會搞不清楚到底誰依賴了誰,保險起見只能全部都加載,性能浪費了太多
,前端大佬搖頭嘆息道
#2. ES6的模組
2.1 ES6之前模組化的痛點
變數衝突
要用window連接各個模組
依賴需要全部載入
還要TMD注意載入順序
模組化是ES6的最大的亮點之一,因為在ES6之前的語法裡從未有過模組化的體系,這對開發大型的、複雜的專案形成了巨大障礙。因為我們無法對專案進行拆分,無法更好地進行多人協作開發。更重要的是,其它大部分語言都支援模組化。
既然語言不支持,那麼如何將模組化引入JS呢?
前端社群就自己制定了一些模組載入方案-這也是CommonJS【伺服器】和AMD、CMD【瀏覽器】的由來。
但是现在ES6引入了模块化的功能,实现起来非常简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
2.2 import和export的用法
import和export语法较为简单,大家去MDN可以看非常详细的讲解,笔者在这里知识用注释简单介绍一下
export语法
// 命名导出 export { name1, name2, …, nameN }; export { variable1 as name1, variable2 as name2, …, nameN }; export let name1, name2, …, nameN; // also var export let name1 = …, name2 = …, …, nameN; // also var, const export function FunctionName() {...} export class ClassName {...} // 默认导出 export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1 as default, … }; // 将其它模块内的导出作为当前文件的导出 export * from …; export { name1, name2, …, nameN } from …; export { import1 as name1, import2 as name2, …, nameN } from …;
import用法
import defaultExport from "module-name"; // 导入默认默认变量 import * as name from "module-name"; // 将模块内所有变量导出,并挂载到name下【name是一个module对象】。什么要有as——为了防止export出来的变量命名冲突 import { export } from "module-name"; // 导入某一个变量 import { export as alias } from "module-name"; // 导入某一个变量并重命名 import { export1 , export2 } from "module-name"; // 导入两个变量 import { export1 , export2 as alias2 , [...] } from "module-name"; // 导入多个变量,同时可以给导入的变量重命名 import defaultExport, { export [ , [...] ] } from "module-name"; // 导入默认变量和多个其它变量 import defaultExport, * as name from "module-name"; // 导入默认变量并重新命名 import "module-name"; // 导入并加载该文件【注意文件内的变量必须要通过export才能被使用】 var promise = import(module-name); // 异步的导入
使用import和export改写第一节的代码
// name.js文件 let names = ['gongxiansheng','pengxiansheng'] export default names
// script1.js import names from './name.js' let module1 = function () { console.log(names[0]) } export default module1
// script2.js import names from './name.js' let module2 = function() { console.log(names[1]) } export default module2
// control.js import module1 from './script1.js' import module2 from './script2.js' setTimeout(() => { module1() }, 1000) module2()
<!--HTML文件--> <script type="module" src="./control.js"></script> <!--注意一定要加上type="module",这样才会将这个script内的代码当做模块来对待-->
2.3 拓展:import和export的一些运行原理
2.3.1 ES6 模块输出的是值的引用,输出接口会动态绑定
其实就是按照数据类型里的引用类型
的概念去理解。
这一点与 CommonJS 规范完全不同。
CommonJS 模块输出的是值的缓存
,不存在动态更新。
// module1.js export var foo = 'bar'; setTimeout(() => foo = 'baz', 500);
// module2.js import {foo} from './module1.js' console.log(foo) setTimeout(() => console.log(foo), 1000); // console的结果 // bar // baz
2.3.2 export可以出现在模块内的任何位置,但不能处于块级作用域内
// 报错 { export let foo = 'bar'; }
2.3.3 import具有提升效果(类似于var),会提升到整个模块的头部,首先执行
console.log(foo) import {foo} from './script1.js'
参考资料:ECMAScript 6 入门
本文纯属原创,为了方便大家理解,小故事,小栗子都是笔者自己想的。如果您觉得对你有帮助,麻烦给个赞,给作者灰暗的生活挥洒挥洒积极向上的正能量,谢谢啦^_^。
相关推荐:
以上是什麼是模組?深刻理解ES6模組的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務
