日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
僅需一篇,搞定前端模塊化

【稿件】前言

在JavaScript發(fā)展初期就是為了實(shí)現(xiàn)簡(jiǎn)單的頁(yè)面交互邏輯,寥寥數(shù)語(yǔ)即可;如今CPU、瀏覽器性能得到了極大的提升,很多頁(yè)面邏輯遷移到了客戶端(表單驗(yàn)證等),隨著web2.0時(shí)代的到來(lái),Ajax技術(shù)得到廣泛應(yīng)用,jQuery等前端庫(kù)層出不窮,前端代碼日益膨脹,此時(shí)在JS方面就會(huì)考慮使用模塊化規(guī)范去管理。

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、吉首ssl等。為數(shù)千家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的吉首網(wǎng)站制作公司

本文內(nèi)容主要有理解模塊化,為什么要模塊化,模塊化的優(yōu)缺點(diǎn)以及模塊化規(guī)范,并且介紹下開發(fā)中***的CommonJS, AMD, ES6、CMD規(guī)范。本文試圖站在小白的角度,用通俗易懂的筆調(diào)介紹這些枯燥無(wú)味的概念,希望諸君閱讀后,對(duì)模塊化編程有個(gè)全新的認(rèn)識(shí)和理解!

如需本文的源代碼,請(qǐng)猛戳源代碼 。

一、模塊化的理解

1.什么是模塊?

  • 將一個(gè)復(fù)雜的程序依據(jù)一定的規(guī)則(規(guī)范)封裝成幾個(gè)塊(文件), 并進(jìn)行組合在一起
  • 塊的內(nèi)部數(shù)據(jù)與實(shí)現(xiàn)是私有的, 只是向外部暴露一些接口(方法)與外部其它模塊通信

2.模塊化的進(jìn)化過(guò)程

  • 全局function模式 : 將不同的功能封裝成不同的全局函數(shù)
    • 編碼: 將不同的功能封裝成不同的全局函數(shù)
    • 問(wèn)題: 污染全局命名空間, 容易引起命名沖突或數(shù)據(jù)不安全,而且模塊成員之間看不出直接關(guān)系 
 
 
 
 
  1. function m1(){  
  2. //...  
  3. }  
  4. function m2(){  
  5. //...  
  6. }  
  • namespace模式 : 簡(jiǎn)單對(duì)象封裝
    • 作用: 減少了全局變量,解決命名沖突
    • 問(wèn)題: 數(shù)據(jù)不安全(外部可以直接修改模塊內(nèi)部的數(shù)據(jù)) 
 
 
 
 
  1. let myModule = {  
  2. data: 'www.baidu.com',  
  3. foo() {  
  4. console.log(`foo() ${this.data}`)  
  5. },  
  6. bar() {  
  7. console.log(`bar() ${this.data}`)  
  8. }  
  9. myModule.data = 'other data' //能直接修改模塊內(nèi)部的數(shù)據(jù)
  10. myModule.foo() // foo() other data

這樣的寫法會(huì)暴露所有模塊成員,內(nèi)部狀態(tài)可以被外部改寫。

  • IIFE模式:匿名函數(shù)自調(diào)用(閉包)
    • 作用: 數(shù)據(jù)是私有的, 外部只能通過(guò)暴露的方法操作
    • 編碼: 將數(shù)據(jù)和行為封裝到一個(gè)函數(shù)內(nèi)部, 通過(guò)給window添加屬性來(lái)向外暴露接口
    • 問(wèn)題: 如果當(dāng)前這個(gè)模塊依賴另一個(gè)模塊怎么辦? 
 
 
 
 
  1. // index.html文件 
  2.  
  3.   
 
 
 
 
  1. // module.js文件 
  2. (function(window) { 
  3.   let data = 'www.baidu.com' 
  4.   //操作數(shù)據(jù)的函數(shù) 
  5.   function foo() { 
  6.     //用于暴露有函數(shù) 
  7.     console.log(`foo() ${data}`) 
  8.   } 
  9.   function bar() { 
  10.     //用于暴露有函數(shù) 
  11.     console.log(`bar() ${data}`) 
  12.     otherFun() //內(nèi)部調(diào)用 
  13.   } 
  14.   function otherFun() { 
  15.     //內(nèi)部私有的函數(shù) 
  16.     console.log('otherFun()') 
  17.   } 
  18.   //暴露行為 
  19.   window.myModule = { foo, bar } //ES6寫法 
  20. })(window)  

***得到的結(jié)果:

  • IIFE模式增強(qiáng) : 引入依賴

這就是現(xiàn)代模塊實(shí)現(xiàn)的基石。

 
 
 
 
  1. // module.js文件 
  2. (function(window, $) { 
  3.   let data = 'www.baidu.com' 
  4.   //操作數(shù)據(jù)的函數(shù) 
  5.   function foo() { 
  6.     //用于暴露有函數(shù) 
  7.     console.log(`foo() ${data}`) 
  8.     $('body').css('background', 'red') 
  9.   } 
  10.   function bar() { 
  11.     //用于暴露有函數(shù) 
  12.     console.log(`bar() ${data}`) 
  13.     otherFun() //內(nèi)部調(diào)用 
  14.   } 
  15.   function otherFun() { 
  16.     //內(nèi)部私有的函數(shù) 
  17.     console.log('otherFun()') 
  18.   } 
  19.   //暴露行為 
  20.   window.myModule = { foo, bar } 
  21. })(window, jQuery)  
 
 
 
 
  1. // index.html文件 
  2.   
  3.   
  4.   
  5.    

上例子通過(guò)jquery方法將頁(yè)面的背景顏色改成紅色,所以必須先引入jQuery庫(kù),就把這個(gè)庫(kù)當(dāng)作參數(shù)傳入。這樣做除了保證模塊的獨(dú)立性,還使得模塊之間的依賴關(guān)系變得明顯。

3. 模塊化的好處

  • 避免命名沖突(減少命名空間污染)
  • 更好的分離, 按需加載
  • 更高復(fù)用性
  • 高可維護(hù)性

4. 引入 

  •  
  •  
  • ***得到如下結(jié)果:

    這種方式缺點(diǎn)很明顯:首先會(huì)發(fā)送多個(gè)請(qǐng)求,其次引入的js文件順序不能搞錯(cuò),否則會(huì)報(bào)錯(cuò)!

    • 使用require.js

    RequireJS是一個(gè)工具庫(kù),主要用于客戶端的模塊管理。它的模塊管理遵守AMD規(guī)范,RequireJS的基本思想是,通過(guò)define方法,將代碼定義為模塊;通過(guò)require方法,實(shí)現(xiàn)代碼的模塊加載。

    接下來(lái)介紹AMD規(guī)范在瀏覽器實(shí)現(xiàn)的步驟:

    ①下載require.js, 并引入

    • 官網(wǎng): http://www.requirejs.cn/
    • github : https://github.com/requirejs/requirejs

    然后將require.js導(dǎo)入項(xiàng)目: js/libs/require.js

    ②創(chuàng)建項(xiàng)目結(jié)構(gòu)

     
     
     
     
    1. |-js   
    2.     |-libs   
    3.       |-require.js   
    4.     |-modules   
    5.       |-alerter.js   
    6.       |-dataService.js   
    7.     |-main.js   
    8.   |-index.html 

    ③定義require.js的模塊代碼

     
     
     
     
    1. // dataService.js文件 
    2. // 定義沒(méi)有依賴的模塊 
    3. define(function() { 
    4.   let msg = 'www.baidu.com' 
    5.   function getMsg() { 
    6.     return msg.toUpperCase() 
    7.   } 
    8.   return { getMsg } // 暴露模塊 
    9. })  
     
     
     
     
    1. //alerter.js文件 
    2. // 定義有依賴的模塊 
    3. define(['dataService'], function(dataService) { 
    4.   let name = 'Tom' 
    5.   function showMsg() { 
    6.     alert(dataService.getMsg() + ', ' + name) 
    7.   } 
    8.   // 暴露模塊 
    9.   return { showMsg } 
    10. })  
     
     
     
     
    1. // main.js文件 
    2. (function() { 
    3.   require.config({ 
    4.     baseUrl: 'js/', //基本路徑 出發(fā)點(diǎn)在根目錄下 
    5.     paths: { 
    6.       //映射: 模塊標(biāo)識(shí)名: 路徑 
    7.       alerter: './modules/alerter', //此處不能寫成alerter.js,會(huì)報(bào)錯(cuò) 
    8.       dataService: './modules/dataService' 
    9.     } 
    10.   }) 
    11.   require(['alerter'], function(alerter) { 
    12.     alerter.showMsg() 
    13.   }) 
    14. })()  
     
     
     
     
    1. // index.html文件 
    2.  
    3.  
    4.    
    5.     Modular Demo 
    6.    
    7.    
    8.      
    9.      
    10.    
    11.  

    ④頁(yè)面引入require.js模塊:

    在index.html引入

    此外在項(xiàng)目中如何引入第三方庫(kù)?只需在上面代碼的基礎(chǔ)稍作修改:

     
     
     
     
    1. // alerter.js文件 
    2. define(['dataService', 'jquery'], function(dataService, $) { 
    3.   let name = 'Tom' 
    4.   function showMsg() { 
    5.     alert(dataService.getMsg() + ', ' + name) 
    6.   } 
    7.   $('body').css('background', 'green') 
    8.   // 暴露模塊 
    9.   return { showMsg } 
    10. })  
     
     
     
     
    1. // main.js文件 
    2. (function() { 
    3.   require.config({ 
    4.     baseUrl: 'js/', //基本路徑 出發(fā)點(diǎn)在根目錄下 
    5.     paths: { 
    6.       //自定義模塊 
    7.       alerter: './modules/alerter', //此處不能寫成alerter.js,會(huì)報(bào)錯(cuò) 
    8.       dataService: './modules/dataService', 
    9.       // 第三方庫(kù)模塊 
    10.       jquery: './libs/jquery-1.10.1' //注意:寫成jQuery會(huì)報(bào)錯(cuò) 
    11.     } 
    12.   }) 
    13.   require(['alerter'], function(alerter) { 
    14.     alerter.showMsg() 
    15.   }) 
    16. })() 

    上例是在alerter.js文件中引入jQuery第三方庫(kù),main.js文件也要有相應(yīng)的路徑配置。

    小結(jié):通過(guò)兩者的比較,可以得出AMD模塊定義的方法非常清晰,不會(huì)污染全局環(huán)境,能夠清楚地顯示依賴關(guān)系。AMD模式可以用于瀏覽器環(huán)境,并且允許非同步加載模塊,也可以根據(jù)需要?jiǎng)討B(tài)加載模塊。

    3.CMD

    CMD規(guī)范專門用于瀏覽器端,模塊的加載是異步的,模塊使用時(shí)才會(huì)加載執(zhí)行。CMD規(guī)范整合了CommonJS和AMD規(guī)范的特點(diǎn)。在 Sea.js 中,所有 JavaScript 模塊都遵循 CMD模塊定義規(guī)范。

    (1)CMD規(guī)范基本語(yǔ)法

    定義暴露模塊:

     
     
     
     
    1. //定義沒(méi)有依賴的模塊 
    2. define(function(require, exports, module){ 
    3.   exports.xxx = value 
    4.   module.exports = value 
    5. })  
     
     
     
     
    1. //定義有依賴的模塊 
    2. define(function(require, exports, module){ 
    3.   //引入依賴模塊(同步) 
    4.   var module2 = require('./module2') 
    5.   //引入依賴模塊(異步) 
    6.     require.async('./module3', function (m3) { 
    7.     }) 
    8.   //暴露模塊 
    9.   exports.xxx = value 
    10. }) 

    引入使用模塊:

     
     
     
     
    1. define(function (require) { 
    2.   var m1 = require('./module1') 
    3.   var m4 = require('./module4') 
    4.   m1.show() 
    5.   m4.show() 
    6. }) 

    (2)sea.js簡(jiǎn)單使用教程

    ①下載sea.js, 并引入

    • 官網(wǎng): http://seajs.org/
    • github : https://github.com/seajs/seajs

    然后將sea.js導(dǎo)入項(xiàng)目: js/libs/sea.js

    ②創(chuàng)建項(xiàng)目結(jié)構(gòu)

     
     
     
     
    1. |-js  
    2.    |-libs   
    3.      |-sea.js   
    4.    |-modules   
    5.      |-module1.js   
    6.      |-module2.js   
    7.      |-module3.js   
    8.      |-module4.js   
    9.      |-main.js   
    10.  |-index.html  

    ③定義sea.js的模塊代碼

     
     
     
     
    1. // module1.js文件 
    2. define(function (require, exports, module) { 
    3.   //內(nèi)部變量數(shù)據(jù) 
    4.   var data = 'atguigu.com' 
    5.   //內(nèi)部函數(shù) 
    6.   function show() { 
    7.     console.log('module1 show() ' + data) 
    8.   } 
    9.   //向外暴露 
    10.   exports.show = show 
    11. }) 
     
     
     
     
    1. // module2.js文件 
    2. define(function (require, exports, module) { 
    3.   module.exports = { 
    4.     msg: 'I Will Back' 
    5.   } 
    6. }) 
     
     
     
     
    1. // module3.js文件 
    2. define(function(require, exports, module) { 
    3.   const API_KEY = 'abc123' 
    4.   exports.API_KEY = API_KEY 
    5. }) 
     
     
     
     
    1. // module4.js文件 
    2. define(function (require, exports, module) { 
    3.   //引入依賴模塊(同步) 
    4.   var module2 = require('./module2') 
    5.   function show() { 
    6.     console.log('module4 show() ' + module2.msg) 
    7.   } 
    8.   exports.show = show 
    9.   //引入依賴模塊(異步) 
    10.   require.async('./module3', function (m3) { 
    11.     console.log('異步引入依賴模塊3  ' + m3.API_KEY) 
    12.   }) 
    13. }) 
     
     
     
     
    1. // main.js文件 
    2. define(function (require) { 
    3.   var m1 = require('./module1') 
    4.   var m4 = require('./module4') 
    5.   m1.show() 
    6.   m4.show() 
    7. }) 

    ④在index.html中引入

     
     
     
     
    1.  
    2.  

    ***得到結(jié)果如下:

    4.ES6模塊化

    ES6 模塊的設(shè)計(jì)思想是盡量的靜態(tài)化,使得編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運(yùn)行時(shí)確定這些東西。比如,CommonJS 模塊就是對(duì)象,輸入時(shí)必須查找對(duì)象屬性。

    (1)ES6模塊化語(yǔ)法

    export命令用于規(guī)定模塊的對(duì)外接口,import命令用于輸入其他模塊提供的功能。

     
     
     
     
    1. /** 定義模塊 math.js **/ 
    2. var basicNum = 0; 
    3. var add = function (a, b) { 
    4.     return a + b; 
    5. }; 
    6. export { basicNum, add }; 
    7. /** 引用模塊 **/ 
    8. import { basicNum, add } from './math'; 
    9. function test(ele) { 
    10.     ele.textContent = add(99 + basicNum); 

    如上例所示,使用import命令的時(shí)候,用戶需要知道所要加載的變量名或函數(shù)名,否則無(wú)法加載。為了給用戶提供方便,讓他們不用閱讀文檔就能加載模塊,就要用到export default命令,為模塊指定默認(rèn)輸出。

     
     
     
     
    1. // export-default.js 
    2. export default function () { 
    3.   console.log('foo'); 
     
     
     
     
    1. // import-default.js 
    2. import customName from './export-default'; 
    3. customName(); // 'foo' 

    模塊默認(rèn)輸出, 其他模塊加載該模塊時(shí),import命令可以為該匿名函數(shù)指定任意名字。

    (2)ES6 模塊與 CommonJS 模塊的差異

    它們有兩個(gè)重大差異:

    ① CommonJS 模塊輸出的是一個(gè)值的拷貝,ES6 模塊輸出的是值的引用。

    ② CommonJS 模塊是運(yùn)行時(shí)加載,ES6 模塊是編譯時(shí)輸出接口。

    第二個(gè)差異是因?yàn)?CommonJS 加載的是一個(gè)對(duì)象(即module.exports屬性),該對(duì)象只有在腳本運(yùn)行完才會(huì)生成。而 ES6 模塊不是對(duì)象,它的對(duì)外接口只是一種靜態(tài)定義,在代碼靜態(tài)解析階段就會(huì)生成。

    下面重點(diǎn)解釋***個(gè)差異,我們還是舉上面那個(gè)CommonJS模塊的加載機(jī)制例子:

     
     
     
     
    1. // lib.js 
    2. export let counter = 3; 
    3. export function incCounter() { 
    4.   counter++; 
    5. // main.js 
    6. import { counter, incCounter } from './lib'; 
    7. console.log(counter); // 3 
    8. incCounter(); 
    9. console.log(counter); // 4 

    ES6 模塊的運(yùn)行機(jī)制與 CommonJS 不一樣。ES6 模塊是動(dòng)態(tài)引用,并且不會(huì)緩存值,模塊里面的變量綁定其所在的模塊。

    (3) ES6-Babel-Browserify使用教程

    簡(jiǎn)單來(lái)說(shuō)就一句話:使用Babel將ES6編譯為ES5代碼,使用Browserify編譯打包js。

    ①定義package.json文件

     
     
     
     
    1. {   
    2.     "name" : "es6-babel-browserify",   
    3.     "version" : "1.0.0"   
    4.   }  

    ②安裝babel-cli, babel-preset-es2015和browserify

    • npm install babel-cli browserify -g
      • npm install babel-preset-es2015 --save-dev
      • preset 預(yù)設(shè)(將es6轉(zhuǎn)換成es5的所有插件打包) 

    ③定義.babelrc文件

     
     
     
     
    1.     "presets": ["es2015"] 
    2.   } 

    ④定義模塊代碼

     
     
     
     
    1. //module1.js文件 
    2. // 分別暴露 
    3. export function foo() { 
    4.   console.log('foo() module1') 
    5. export function bar() { 
    6.   console.log('bar() module1') 
     
     
     
     
    1. //module2.js文件 
    2. // 統(tǒng)一暴露 
    3. function fun1() { 
    4.   console.log('fun1() module2') 
    5. function fun2() { 
    6.   console.log('fun2() module2') 
    7. export { fun1, fun2 } 
     
     
     
     
    1. //module3.js文件 
    2. // 默認(rèn)暴露 可以暴露任意數(shù)據(jù)類項(xiàng),暴露什么數(shù)據(jù),接收到就是什么數(shù)據(jù) 
    3. export default () => { 
    4.   console.log('默認(rèn)暴露') 
     
     
     
     
    1. // app.js文件 
    2. import { foo, bar } from './module1' 
    3. import { fun1, fun2 } from './module2' 
    4. import module3 from './module3' 
    5. foo() 
    6. bar() 
    7. fun1() 
    8. fun2() 
    9. module3() 

    ⑤ 編譯并在index.html中引入

    • 使用Babel將ES6編譯為ES5代碼(但包含CommonJS語(yǔ)法) : babel js/src -d js/lib
    • 使用Browserify編譯js : browserify js/lib/app.js -o js/lib/bundle.js 

    然后在index.html文件中引入:

     
     
     
     
    1.   

    ***得到如下結(jié)果:

    此外第三方庫(kù)(以jQuery為例)如何引入呢?

    首先安裝依賴npm install jquery@1

    然后在app.js文件中引入:

     
     
     
     
    1. //app.js文件 
    2. import { foo, bar } from './module1' 
    3. import { fun1, fun2 } from './module2' 
    4. import module3 from './module3' 
    5. import $ from 'jquery' 
    6.  
    7. foo() 
    8. bar() 
    9. fun1() 
    10. fun2() 
    11. module3() 
    12. $('body').css('background', 'green') 

    三、總結(jié)

    • CommonJS規(guī)范主要用于服務(wù)端編程,加載模塊是同步的,這并不適合在瀏覽器環(huán)境,因?yàn)橥揭馕吨枞虞d,瀏覽器資源是異步加載的,因此有了AMD CMD解決方案。
    • AMD規(guī)范在瀏覽器環(huán)境中異步加載模塊,而且可以并行加載多個(gè)模塊。不過(guò),AMD規(guī)范開發(fā)成本高,代碼的閱讀和書寫比較困難,模塊定義方式的語(yǔ)義不順暢。
    • CMD規(guī)范與AMD規(guī)范很相似,都用于瀏覽器編程,依賴就近,延遲執(zhí)行,可以很容易在Node.js中運(yùn)行。不過(guò),依賴SPM 打包,模塊的加載邏輯偏重
    • ES6 在語(yǔ)言標(biāo)準(zhǔn)的層面上,實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單,完全可以取代 CommonJS 和 AMD 規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案。

    參考文章 

    • 前端模塊化開發(fā)那點(diǎn)歷史
    • CommonJS,AMD,CMD區(qū)別
    • AMD 和 CMD 的區(qū)別有哪些?
    • Javascript模塊化編程
    • Javascript標(biāo)準(zhǔn)參考教程
    • CMD 模塊定義規(guī)范
    • 理解CommonJS、AMD、CMD三種規(guī)范

    作者:浪里行舟,慕課網(wǎng)認(rèn)證作者,前端愛好者,立志往全棧工程師發(fā)展,從事前端一年多,目前技術(shù)棧有vue全家桶、ES6以及l(fā)ess等,樂(lè)于分享,最近一年寫了五六十篇原創(chuàng)技術(shù)文章,得到諸多好評(píng)!

    【原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為.com】


    文章題目:僅需一篇,搞定前端模塊化
    文章分享:http://www.dlmjj.cn/article/dpscijc.html