日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

模块化加载_前端模块化简单总结

發布時間:2025/3/19 HTML 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模块化加载_前端模块化简单总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

來源 |?http://www.fly63.com/article/detial/9827

前言

JavaScript初期就是為了實現簡單的頁面交互邏輯,如今CPU、瀏覽器性能得到了極大的提升,很多頁面邏輯遷移到了客戶端,前端代碼日益膨脹,此時在js方面就會考慮怎么樣來管理使用模塊化規范去管理。無論是什么語言一旦發展到一定地步,其工程化能力和可維護性勢必得到相應的發展。模塊化這件事,無論在哪個編程領域都是常見的事情,模塊化存在的意義就是為了增加可復用性,以盡可能少的代碼是實現個性化的需求。同為前端三劍客之一的 css 早在 2.1 的版本就提出了?@import 來實現模塊化,但是 JavaScript 直到 ES6 才出現官方的模塊化方案:ES Module (import、export)。盡管早期 JavaScript 語言規范上不支持模塊化,但這并沒有阻止 JavaScript 的發展,官方沒有模塊化標準開發者們就開始自己創建規范,自己實現規范。

前端模塊化

JavaScript 在早期的設計中就沒有模塊、包甚至類的概念,雖然 ES6 中有了 class 關鍵字,那也只是個語法糖。隨意隨著項目復雜度的增加,開發者必然需要模擬類的功能,來隔離、封裝、組織復雜的 JavaScript 代碼,而這種封裝和隔離,也被被我們稱之為模塊化。模塊就是一個實現特定功能的文件 or 代碼塊。隨著前端工程體系建設的愈發成熟,或許模塊化的概念已經在前端圈子里已經耳熟能詳了。但是對于很多開發者而言,ES6 中的?export、import,nodejs?中的?require、exports.xx、module.exports到底有什么區別?為什么又有 CommonJS,又有?AMD,CMD,UMD?區別是什么?甚至我們在編寫 ts 文件的時候,還需要在配置文件里面說明什么模塊方式,在項目中使用的時候,我們又是否真正知道,你用的到底是基于哪一種規范的模塊化?

模塊化的價值

可維護性,每一個模塊都是獨立的。良好的設計能夠極大的降低項目的耦合度。以便于其能獨立于別的功能被整改。至少維護一個獨立的功能模塊,比維護一坨凌亂的代碼要容易很多。減少全局變量污染,前端開發的初期,我們都在為全局變量而頭疼,因為經常會觸發一些難以排查且非技術性的 bug。當一些無關的代碼一不小心重名了全局變量,我們就會遇到煩人的“命名空間污染”的問題。在模塊化規范沒有確定之前,其實我們都在極力的避免于此。(后文會介紹)可復用性,前端模塊功能的封裝,極大的提高了代碼的可復用性。這點應該就不用詳細說明了。想想從 npm 上找 package 的時候,是在干啥?方便管理依賴關系,在模塊化規范沒有完全確定的時候,模塊之間相互依賴的關系非常的模糊,完全取決于 js 文件引入的順序。粗俗!絲毫沒有技術含量,不僅依賴模糊且難以維護。

模塊化的進化過程

1、函數封裝

回到我們剛剛說的模塊的定義,模塊就是一個實現特定功能的文件 or 代碼塊(這是我自己給定義的)。專業定義是,在程序設計中,為完成某一功能所需的一段程序或子程序;或指能由編譯程序、裝配程序等處理的獨立程序單位;或指大型軟件系統的一部分。而函數的一個功能就是實現特定邏輯的一組語句打包。并且 JavaScript 的作用域就是基于函數的,所以最原始之處,函數必然是作為模塊化的第一步。將不同的功能封裝成不同的函數編碼: 將不同的功能封裝成不同的全局函數問題: 污染全局命名空間, 容易引起命名沖突或數據不安全,而且模塊成員之間看不出直接關系,模塊之間的關系模糊。//函數1function fn1(){//statement}//函數2function fn2(){//statement}

2、namespace模式?

也可以理解為對象封裝,其實就是把相關函數、變量在外面加了一層。

let module1 = {let tag : 1,let name:'module1', fun1(){console.log('this is fun1') }, fun2(){console.log('this is fun2') }}

我們在使用的時候呢,就直接

module1.fun2();

優點

一定程度上優化了命名沖突,降低了全局變量污染的風險

有一定的模塊封裝和隔離,并且還可以進一步語義化一些

缺點

并沒有實質上改變命名沖突的問題

外部可以隨意修改內部成員變量,還是容易產生意外風險

3、IIFE模式:立即執行匿名函數(閉包)

let global = 'Hello, I am a global variable :)';(function () {// 在函數的作用域中下面的變量是私有的const myGrades = [93, 95, 88, 0, 55, 91];let average = function() {let total = myGrades.reduce(function(accumulator, item) {return accumulator + item}, 0);return 'Your average grade is ' + total / myGrades.length + '.'; }let failing = function(){let failingGrades = myGrades.filter(function(item) {return item < 70;});return 'You failed ' + failingGrades.length + ' times.'; }console.log(failing());console.log(global);// 需要暴露的apireturn {// something}}());// 控制臺顯示:'You failed 2 times.'// 控制臺顯示:'Hello, I am a global variable :)'

這種方法的好處在于,你可以在函數內部使用局部變量,而不會意外覆蓋同名全局變量,但仍然能夠訪問到全局變量

類似如上的?IIFE?,還有非常多的演進寫法

比如引入依賴:

把內部需要的變量傳進去。

// module.js文件(function(window, $) {let data = 'www.baidu.com'//操作數據的函數function foo() {//用于暴露有函數console.log(`foo() ${data}`) $('body').css('background', 'red') }function bar() {//用于暴露有函數console.log(`bar() ${data}`) otherFun() //內部調用 }function otherFun() {//內部私有的函數console.log('otherFun()') }//暴露行為window.myModule = { foo, bar }})(window, jQuery)

使用

// index.html文件<script type="text/javascript" src="jquery-1.10.1.js">script><script type="text/javascript" src="module.js">script><script type="text/javascript"> myModule.foo()script>

優點

實現了基本的封裝

只暴露對外的方法操作,利用閉包實現了類似?public?和?private?的概念

缺點

模塊依賴關系模糊

模塊與模塊之間不好管理

上述的所有解決方案,雖然每種方法都可行,但是始終沒有哪一種可以很好的解決變量污染、各個模塊之間依賴關系清晰、方便管理、與第三方代碼方便集成。

隨著大前端時代的到來,在2009年提出了 CommonJS 規范,并且nodeJs 直接用該規范來管理模塊化,隨著時間的遷移,現在 JavaScript 模塊規范也就有了:CommonJS、AMD、CMD、UMD、ES6 模塊化。

4、CommonJS

CommonJS 是 JavaScript 的一個模塊化規范(http://www.commonjs.org/),主要用于服務端Nodejs 中。

根據規范,每一個文件既是一個模塊,其內部定義的變量是屬于這個模塊的,不會污染全局變量。每個模塊內部,module變量代表當前模塊,這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口。

加載某個模塊,其實是加載該模塊的module.exports屬性。

CommonJS 的核心思想是通過 require 方法來同步加載所依賴的模塊,然后通過 exports 或者 module.exprots 來導出對外暴露的接口。?

基本用法

暴露模塊:module.exports = value 或 exports.xxx = value

引入模塊:require(xxx),如果是第三方模塊,xxx為模塊名;如果是自定義模塊,xxx為模塊文件路徑。

// example.jslet x = 5;let addX = function (value) {return value + x;};module.exports.x = x;module.exports.addX = addX;let example = require('./example.js');console.log(example.x); // 5console.log(example.addX(1)); // 6

require命令用于加載模塊文件。require命令的基本功能是,讀入并執行一個JavaScript文件,然后返回該模塊的exports對象,如果沒有發現指定模塊,會報錯,如果存在多個 exports ?只有第一個exports 有效。

require 是加載這個文件然后執行,在返回、輸出 exports 這個對象。

console.log('開始加載了') // 會輸出 開始加載了function run (val) {console.log(val)}

特點

以文件為一個單元模塊,代碼運行在模塊作用域內,不會污染全局變量

同步加載模塊,在服務端直接讀取本地磁盤沒問題,不太適用于瀏覽器

模塊可以加載多次,但是只會在第一次加載時運行,然后在加載,就是讀取的緩存文件。需清理緩存后才可再次讀取文件內容

模塊加載的順序,按照其在代碼中出現的順序

導出的是值的拷貝,這一點和 ES6 有著很大的不同(后面會介紹到)

補充知識點

Node 中,一個文件是一個模塊->module

源碼定義如下:

function Module(id = '', parent) {this.id = id;this.path = path.dirname(id);this.exports = {};this.parent = parent; updateChildren(parent, this, false);this.filename = null;this.loaded = false;this.children = [];}//實例化一個模塊var module = new Module(filename, parent);

CommonJS 的一個模塊,就是一個腳本文件。require命令第一次加載該腳本,就會執行整個腳本,然后在內存生成一個對象。

{id: '...', exports: { ... },loaded: true, ...}

上面代碼就是 Node 內部加載模塊后生成的一個對象。該對象的id屬性是模塊名,exports屬性是模塊輸出的各個接口,loaded屬性是一個布爾值,表示該模塊的腳本是否執行完畢。其他還有很多屬性。

以后需要用到這個模塊的時候,就會到exports屬性上面取值。即使再次執行require命令,也不會再次執行該模塊,而是到緩存之中取值。

也就是說,CommonJS 模塊無論加載多少次,都只會在第一次加載時運行一次,以后再加載,就返回第一次運行的結果,除非手動清除系統緩存。

關于AMD、CMD

CommonJS 在 Node.js 環境下取得了很不錯的成功,很多人想把commonJs 規范推向瀏覽器端,但是瀏覽器不能像服務器那樣直接讀取磁盤上的內容所以又有了后面的AMD、CMD規范。

ES6 在語言標準的層面上,實現了模塊功能,而且實現得相當簡單,完全可以取代現有的 CommonJS 和 AMD 規范,成為瀏覽器和服務器通用的模塊解決方案,因為我自己也是在近幾年才做前端, AMD、CMD 并沒有太多使用,所以AMD、CMD 這里只是做簡單的介紹。

5、AMD

AMD 全稱為?Asynchromous Module Definition(異步模塊定義)

AMD 是?RequireJS?在推廣過程中對模塊定義的規范化產出,它是一個在瀏覽器端模塊化開發的規范。

AMD 模式可以用于瀏覽器環境并且允許異步加載模塊,同時又能保證正確的順序,也可以按需動態加載模塊。

特點

異步加載模塊,不會造成因網絡問題而出現的假死

顯式地列出其依賴關系,并以函數(定義此模塊的那個函數)參數的形式將這些依賴進行注入

在模塊開始時,加載所有所需依賴

定義模塊

define(id?: String, dependencies?: String[], callback: Function|Object);

id,一個可選參數,類似給模塊取個名字,但是卻是模塊的唯一標識。如果沒有提供則取腳本的文件名

dependence,依賴的模塊數組

callback,工廠方法,模塊初始化的一些操作。如果是函數,只被執行一次。如果是對象,則為模塊的輸出值

使用模塊

require([moduleName],callback);

使用

//article.js文件// 定義有依賴的模塊define(['user'], function(user) {let name = 'THE LAST TIME'function consoleMsg() {console.log(`${name} by ${user.getAuthor()}`); }// 暴露模塊return { consoleMsg }})// 調用 article 模塊種的 consoleMsgrequire(['article'], function(alerter) { article.consoleMsg() })

關于 require.js 的使用,仔細看文檔,其實還是有很多知識點的。但是鑒于我們著實現在使用不多(我也不熟),所以這里也就參考網上優秀文章和自己實踐,拋磚引玉。

6、CMD

CMD 即Common Module Definition通用模塊定義,CMD 是 SeaJS 在推廣過程中對模塊定義的規范化產出,是阿里的玉伯提出來,它和 AMD 其實非常的相似,文件即為模塊。

CMD最主要的區別是實現了按需加載,推崇依賴就近的原則,模塊延遲執行,而 AMD 所依賴模塊式提前執行(requireJS 2.0 后也改為了延遲執行)

所以AMD和CMD最大的區別是對依賴模塊的執行時機處理不同,注意不是加載的時機或者方式不同。

CMD 規范盡量保持簡單,并與 CommonJS 規范保持了很大的兼容性。

通過 CMD 規范書寫的模塊,可以很容易在 Node.js 中運行。

在 CMD 規范中,一個模塊就是一個文件。格式如下:

define(factory);

define?是一個全局函數,用來定義模塊,參數factory可以是對象、字符串、函數

factory 為對象、字符串時,表示模塊的接口就是該對象、字符串。比如可以如下定義一個 JSON 數據模塊:

define({ "foo": "bar" });

也可以通過字符串定義模板模塊:

define('I am a template. My name is {{name}}.');

factory 為函數時,表示是模塊的構造方法。

執行該構造方法,可以得到模塊向外提供的接口。factory 方法在執行時,默認會傳入三個參數:require、exports 和 module:

define(function(require, exports, module) {// 模塊代碼});

使用sea.js

/** sea.js **/// 定義模塊 math.jsdefine(function(require, exports, module) {var $ = require('jquery.js');var add = function(a,b){return a+b; } exports.add = add;});// 加載模塊seajs.use(['math.js'], function(math){var sum = math.add(1+2);});

關于 sea.js 的使用,仔細看文檔,其實還是有很多知識點的。但是鑒于我們著實現在使用不多(我也不熟),所以這里也就參考網上優秀文章和自己實踐,拋磚引玉。

?7、UMD

UMD 是 AMD 和 CommonJS 的綜合產物。如上所說,AMD 的用武之地是瀏覽器,非阻塞式加載。CommonJS 主要用于服務端 Nodejs 中使用。所以人們就想到了一個通用的模式 UMD(universal module definition)。來解決跨平臺的問題。
沒錯!就是 ifElse 的寫法。
核心思想就是:先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js模塊模式。
在判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。

(function (root, factory) {if (typeof define === 'function' && define.amd) {//AMD define(['jquery'], factory); } else if (typeof exports === 'object') {//Node, CommonJS之類的module.exports = factory(require('jquery')); } else {//瀏覽器全局變量(root 即 window) root.returnExports = factory(root.jQuery); }}(this, function ($) {//方法function myFunc(){};//暴露公共方法return myFunc;}));

8、ES Module

在 ES Module 之前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用于服務器,后者用于瀏覽器。

ES Module 在語言標準的層面上,實現了模塊功能,而且實現得相當簡單,完全可以取代 CommonJS 和 AMD 規范,成為瀏覽器和服務器通用的模塊解決方案。

ES Module 的設計思想是盡量的靜態化,使得編譯時就能確定模塊的依賴關系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時確定這些東西。

CommonJS 和 AMD 模塊,其本質是在運行時生成一個對象進行導出,稱為“運行時加載”,沒法進行“編譯優化”,而 ES Module 不是對象,而是通過 export 命令顯式指定輸出的代碼,再通過 import 命令輸入。

這稱為“編譯時加載”或者靜態加載,即 ES Module 可以在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。當然,這也導致了沒法引用 ES Module 模塊本身,因為它不是對象。

由于 ES Module 是編譯時加載,使得靜態分析成為可能。有了它,就能進一步拓寬 JavaScript 的語法,比如引入宏(macro)和類型檢驗(type system)這些只能靠靜態分析實現的功能。

特點

靜態編譯

輸出的值引用,而非值拷貝

import?只能寫在頂層,因為是靜態語法

9、CommonJs、ESM 區別

CommonJsES6 Module
運行時加載;CommonJs模塊就是對象(module.exports屬性)),即在輸入時是先加載整個模塊、執行模塊,生成一個對象,然后再從這個對象上面讀取方法。編譯時加載;ES6 模塊不是對象,而是通過 export 命令顯式指定輸出的代碼,import時采用靜態命令的形式。即在import時可以指定加載某個輸出值,而不是加載整個模塊。
輸出的是值的拷貝(一旦輸出一個值,模塊內部的變化就影響不到這個值。)輸出的是值的引用(JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執行時,再根據這個只讀引用,到被加載的那個模塊里面去取值。即原始值變了,import加載的值也會跟著變。因此,ES6 模塊是動態引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊。)

差異

CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。

CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。

加載 & 編譯

因為 CommonJS 加載的是一個對象(module.exports),對象只有在有腳本運行的時候才能生成。而 ES6 模塊不是一個對象,只是一個靜態的定義。在代碼解析階段就會生成。

ES6 模塊是編譯時輸出接口,因此有如下2個特點:

import?命令會被 JS 引擎靜態分析,優先于模塊內的其他內容執行

export 命令會有變量聲明提升的效果,所以import 和 export 命令在模塊中的位置并不影響程序的輸出。

異步加載模塊,不會造成因網絡問題而出現的假死。

顯式地列出其依賴關系,并以函數(定義此模塊的那個函數)參數的形式將這些依賴進行注入。

在模塊開始時,加載所有所需依賴。

總結

以上是生活随笔為你收集整理的模块化加载_前端模块化简单总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 182tv福利视频 | av男人天堂av | 不卡黄色 | 影音先锋中文字幕在线播放 | 亚洲精品香蕉 | 国产女人18毛片水18精 | 伊人网综合 | 中文字幕色 | 午夜免费毛片 | 国产主播啪啪 | 激情久久av一区av二区av三区 | 国产精品一区二区av日韩在线 | 大桥未久中文字幕 | 特级西西人体444www高清 | www.五月婷婷 | 97久久国产亚洲精品超碰热 | 最新国产一区 | 亚洲国产精品无码久久 | 亚洲天堂无吗 | 亚洲欧美激情另类 | 久久夜色网 | 视频一区免费 | 性欧美18一19内谢 | 91们嫩草伦理 | 天天看片天天干 | 精品国产乱码一区二 | 欧美熟妇激情一区二区三区 | 成人午夜看片 | 国产精品美女自拍视频 | 丁香激情五月少妇 | 国产精品视频在线播放 | 伊人国产视频 | 蜜桃免费在线视频 | 欧美精品hd| 色婷婷欧美 | 国产一区免费看 | 蜜乳av中文字幕 | 伊人久久中文字幕 | 香蕉国产精品视频 | 佐佐木明希电影 | 国产91白丝在一线播放 | 久久久久亚洲国产 | 波多野结衣影片 | 女人16一毛片 | 国产性生活网站 | 精品人妻一区二区三区四区不卡 | 国产精品女同一区二区 | 午夜视频在线免费 | 桃谷绘里香番号 | 91久久一区二区 | 久久精品国产亚洲AV成人婷婷 | 欧美久久久影院 | 男人天堂网在线 | 特级西西444www大精品视频免费看 | 中文字幕在线视频精品 | 人妖被c到高潮欧美gay | 182av| 性视频在线播放 | 美女少妇一区二区 | 欧美第十页| 99热成人| 午夜在线观看av | 亚洲精品福利视频 | 亚洲成人91| 国产亚洲一区二区不卡 | 日日干夜夜爱 | 91九色视频在线观看 | 啪啪福利社 | 久草三级 | 亚洲综合情| 天堂综合网久久 | 亚洲大尺度网站 | 中国无码人妻丰满熟妇啪啪软件 | 老司机免费在线视频 | 中国肥胖女人真人毛片 | 久久精品午夜 | 亚洲视频图片小说 | 国产精品久久久精品 | wwwav视频| 国产伦精品一区二区三区视频痴汉 | 成人在线观 | 欧美夫妻性生活视频 | 亚洲影院一区二区三区 | 亚洲乱子伦 | 五月婷婷综合网 | 亚洲天堂av在线播放 | 操极品女神 | 日韩欧美黄色网址 | 男人天堂成人 | 亚洲色图一区二区 | 波多野结衣一二三四区 | 老子影院午夜精品无码 | 国产免费自拍视频 | 激情五月色婷婷 | 激情小视频在线观看 | 国产精品aaa| 国内激情视频 | 婷婷六月天在线 | 极品销魂美女一区二区三区 |