国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

前端模塊化詳解(完整版)

Pines_Cheng / 1706人閱讀

摘要:二模塊化規范概述應用由模塊組成,采用模塊規范。模塊化語法命令用于規定模塊的對外接口,命令用于輸入其他模塊提供的功能。

前言

在JavaScript發展初期就是為了實現簡單的頁面交互邏輯,寥寥數語即可;如今CPU、瀏覽器性能得到了極大的提升,很多頁面邏輯遷移到了客戶端(表單驗證等),隨著web2.0時代的到來,Ajax技術得到廣泛應用,jQuery等前端庫層出不窮,前端代碼日益膨脹,此時在JS方面就會考慮使用模塊化規范去管理。
本文內容主要有理解模塊化,為什么要模塊化,模塊化的優缺點以及模塊化規范,并且介紹下開發中最流行的CommonJS, AMD, ES6、CMD規范。本文試圖站在小白的角度,用通俗易懂的筆調介紹這些枯燥無味的概念,希望諸君閱讀后,對模塊化編程有個全新的認識和理解!

建議下載本文源代碼,自己動手敲一遍,請猛戳GitHub個人博客

一、模塊化的理解 1.什么是模塊?

將一個復雜的程序依據一定的規則(規范)封裝成幾個塊(文件), 并進行組合在一起

塊的內部數據與實現是私有的, 只是向外部暴露一些接口(方法)與外部其它模塊通信

2.模塊化的進化過程

全局function模式 : 將不同的功能封裝成不同的全局函數

編碼: 將不同的功能封裝成不同的全局函數

問題: 污染全局命名空間, 容易引起命名沖突或數據不安全,而且模塊成員之間看不出直接關系

function m1(){
  //...
}
function m2(){
  //...
}

namespace模式 : 簡單對象封裝

作用: 減少了全局變量,解決命名沖突

問題: 數據不安全(外部可以直接修改模塊內部的數據)

let myModule = {
  data: "www.baidu.com",
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}
myModule.data = "other data" //能直接修改模塊內部的數據
myModule.foo() // foo() other data

這樣的寫法會暴露所有模塊成員,內部狀態可以被外部改寫。

IIFE模式:匿名函數自調用(閉包)

作用: 數據是私有的, 外部只能通過暴露的方法操作

編碼: 將數據和行為封裝到一個函數內部, 通過給window添加屬性來向外暴露接口

問題: 如果當前這個模塊依賴另一個模塊怎么辦?

// index.html文件

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

最后得到的結果:

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文件
  
  
  
  

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

3. 模塊化的好處

避免命名沖突(減少命名空間污染)

更好的分離, 按需加載

更高復用性

高可維護性

4. 引入多個

2.AMD

CommonJS規范加載模塊是同步的,也就是說,只有加載完成,才能執行后面的操作。AMD規范則是非同步加載模塊,允許指定回調函數。由于Node.js主要用于服務器編程,模塊文件一般都已經存在于本地硬盤,所以加載起來比較快,不用考慮非同步加載的方式,所以CommonJS規范比較適用。但是,如果是瀏覽器環境,要從服務器端加載模塊,這時就必須采用非同步模式,因此瀏覽器端一般采用AMD規范。此外AMD規范比CommonJS規范在瀏覽器端實現要來著早。

(1)AMD規范基本語法

定義暴露模塊:

//定義沒有依賴的模塊
define(function(){
   return 模塊
})
//定義有依賴的模塊
define(["module1", "module2"], function(m1, m2){
   return 模塊
})

引入使用模塊:

require(["module1", "module2"], function(m1, m2){
   使用m1/m2
})
(2)未使用AMD規范與使用require.js

通過比較兩者的實現方法,來說明使用AMD規范的好處。

未使用AMD規范

// dataService.js文件
(function (window) {
  let msg = "www.baidu.com"
  function getMsg() {
    return msg.toUpperCase()
  }
  window.dataService = {getMsg}
})(window)
 // alerter.js文件
(function (window, dataService) {
  let name = "Tom"
  function showMsg() {
    alert(dataService.getMsg() + ", " + name)
  }
  window.alerter = {showMsg}
})(window, dataService)
// main.js文件
(function (alerter) {
  alerter.showMsg()
})(alerter)
// index.html文件

Modular Demo 1: 未使用AMD(require.js)

最后得到如下結果:

這種方式缺點很明顯:首先會發送多個請求,其次引入的js文件順序不能搞錯,否則會報錯!

使用require.js

RequireJS是一個工具庫,主要用于客戶端的模塊管理。它的模塊管理遵守AMD規范,RequireJS的基本思想是,通過define方法,將代碼定義為模塊;通過require方法,實現代碼的模塊加載
接下來介紹AMD規范在瀏覽器實現的步驟:

①下載require.js, 并引入

官網: http://www.requirejs.cn/

github : https://github.com/requirejs/requirejs

然后將require.js導入項目: js/libs/require.js

②創建項目結構
|-js
  |-libs
    |-require.js
  |-modules
    |-alerter.js
    |-dataService.js
  |-main.js
|-index.html
③定義require.js的模塊代碼
// dataService.js文件 
// 定義沒有依賴的模塊
define(function() {
  let msg = "www.baidu.com"
  function getMsg() {
    return msg.toUpperCase()
  }
  return { getMsg } // 暴露模塊
})
//alerter.js文件
// 定義有依賴的模塊
define(["dataService"], function(dataService) {
  let name = "Tom"
  function showMsg() {
    alert(dataService.getMsg() + ", " + name)
  }
  // 暴露模塊
  return { showMsg }
})
// main.js文件
(function() {
  require.config({
    baseUrl: "js/", //基本路徑 出發點在根目錄下
    paths: {
      //映射: 模塊標識名: 路徑
      alerter: "./modules/alerter", //此處不能寫成alerter.js,會報錯
      dataService: "./modules/dataService"
    }
  })
  require(["alerter"], function(alerter) {
    alerter.showMsg()
  })
})()
// index.html文件


  
    Modular Demo
  
  
    
    
  
④頁面引入require.js模塊:

在index.html引入

此外在項目中如何引入第三方庫?只需在上面代碼的基礎稍作修改:

// alerter.js文件
define(["dataService", "jquery"], function(dataService, $) {
  let name = "Tom"
  function showMsg() {
    alert(dataService.getMsg() + ", " + name)
  }
  $("body").css("background", "green")
  // 暴露模塊
  return { showMsg }
})
// main.js文件
(function() {
  require.config({
    baseUrl: "js/", //基本路徑 出發點在根目錄下
    paths: {
      //自定義模塊
      alerter: "./modules/alerter", //此處不能寫成alerter.js,會報錯
      dataService: "./modules/dataService",
      // 第三方庫模塊
      jquery: "./libs/jquery-1.10.1" //注意:寫成jQuery會報錯
    }
  })
  require(["alerter"], function(alerter) {
    alerter.showMsg()
  })
})()

上例是在alerter.js文件中引入jQuery第三方庫,main.js文件也要有相應的路徑配置。
小結:通過兩者的比較,可以得出AMD模塊定義的方法非常清晰,不會污染全局環境,能夠清楚地顯示依賴關系。AMD模式可以用于瀏覽器環境,并且允許非同步加載模塊,也可以根據需要動態加載模塊。

3.CMD

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

(1)CMD規范基本語法

定義暴露模塊:

//定義沒有依賴的模塊
define(function(require, exports, module){
  exports.xxx = value
  module.exports = value
})
//定義有依賴的模塊
define(function(require, exports, module){
  //引入依賴模塊(同步)
  var module2 = require("./module2")
  //引入依賴模塊(異步)
    require.async("./module3", function (m3) {
    })
  //暴露模塊
  exports.xxx = value
})

引入使用模塊:

define(function (require) {
  var m1 = require("./module1")
  var m4 = require("./module4")
  m1.show()
  m4.show()
})
(2)sea.js簡單使用教程 ①下載sea.js, 并引入

官網: http://seajs.org/

github : https://github.com/seajs/seajs

然后將sea.js導入項目: js/libs/sea.js

②創建項目結構
|-js
  |-libs
    |-sea.js
  |-modules
    |-module1.js
    |-module2.js
    |-module3.js
    |-module4.js
    |-main.js
|-index.html
③定義sea.js的模塊代碼
// module1.js文件
define(function (require, exports, module) {
  //內部變量數據
  var data = "atguigu.com"
  //內部函數
  function show() {
    console.log("module1 show() " + data)
  }
  //向外暴露
  exports.show = show
})
// module2.js文件
define(function (require, exports, module) {
  module.exports = {
    msg: "I Will Back"
  }
})
// module3.js文件
define(function(require, exports, module) {
  const API_KEY = "abc123"
  exports.API_KEY = API_KEY
})
// module4.js文件
define(function (require, exports, module) {
  //引入依賴模塊(同步)
  var module2 = require("./module2")
  function show() {
    console.log("module4 show() " + module2.msg)
  }
  exports.show = show
  //引入依賴模塊(異步)
  require.async("./module3", function (m3) {
    console.log("異步引入依賴模塊3  " + m3.API_KEY)
  })
})
// main.js文件
define(function (require) {
  var m1 = require("./module1")
  var m4 = require("./module4")
  m1.show()
  m4.show()
})
④在index.html中引入

最后得到結果如下:

4.ES6模塊化

ES6 模塊的設計思想是盡量的靜態化,使得編譯時就能確定模塊的依賴關系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時確定這些東西。比如,CommonJS 模塊就是對象,輸入時必須查找對象屬性。

(1)ES6模塊化語法

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

/** 定義模塊 math.js **/
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };
/** 引用模塊 **/
import { basicNum, add } from "./math";
function test(ele) {
    ele.textContent = add(99 + basicNum);
}

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

// export-default.js
export default function () {
  console.log("foo");
}
// import-default.js
import customName from "./export-default";
customName(); // "foo"

模塊默認輸出, 其他模塊加載該模塊時,import命令可以為該匿名函數指定任意名字。

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

它們有兩個重大差異:

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

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

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

下面重點解釋第一個差異,我們還是舉上面那個CommonJS模塊的加載機制例子:

// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}
// main.js
import { counter, incCounter } from "./lib";
console.log(counter); // 3
incCounter();
console.log(counter); // 4

ES6 模塊的運行機制與 CommonJS 不一樣。ES6 模塊是動態引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊

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

簡單來說就一句話:使用Babel將ES6編譯為ES5代碼,使用Browserify編譯打包js

①定義package.json文件
 {
   "name" : "es6-babel-browserify",
   "version" : "1.0.0"
 }
②安裝babel-cli, babel-preset-es2015和browserify

npm install babel-cli browserify -g

npm install babel-preset-es2015 --save-dev

preset 預設(將es6轉換成es5的所有插件打包)

③定義.babelrc文件
  {
    "presets": ["es2015"]
  }
④定義模塊代碼
//module1.js文件
// 分別暴露
export function foo() {
  console.log("foo() module1")
}
export function bar() {
  console.log("bar() module1")
}
//module2.js文件
// 統一暴露
function fun1() {
  console.log("fun1() module2")
}
function fun2() {
  console.log("fun2() module2")
}
export { fun1, fun2 }
//module3.js文件
// 默認暴露 可以暴露任意數據類項,暴露什么數據,接收到就是什么數據
export default () => {
  console.log("默認暴露")
}
// app.js文件
import { foo, bar } from "./module1"
import { fun1, fun2 } from "./module2"
import module3 from "./module3"
foo()
bar()
fun1()
fun2()
module3()
⑤ 編譯并在index.html中引入

使用Babel將ES6編譯為ES5代碼(但包含CommonJS語法) : babel js/src -d js/lib

使用Browserify編譯js : browserify js/lib/app.js -o js/lib/bundle.js

然后在index.html文件中引入

 

最后得到如下結果:

此外第三方庫(以jQuery為例)如何引入呢
首先安裝依賴npm install jquery@1
然后在app.js文件中引入

//app.js文件
import { foo, bar } from "./module1"
import { fun1, fun2 } from "./module2"
import module3 from "./module3"
import $ from "jquery"

foo()
bar()
fun1()
fun2()
module3()
$("body").css("background", "green")
三、總結

CommonJS規范主要用于服務端編程,加載模塊是同步的,這并不適合在瀏覽器環境,因為同步意味著阻塞加載,瀏覽器資源是異步加載的,因此有了AMD CMD解決方案。

AMD規范在瀏覽器環境中異步加載模塊,而且可以并行加載多個模塊。不過,AMD規范開發成本高,代碼的閱讀和書寫比較困難,模塊定義方式的語義不順暢。

CMD規范與AMD規范很相似,都用于瀏覽器編程,依賴就近,延遲執行,可以很容易在Node.js中運行。不過,依賴SPM 打包,模塊的加載邏輯偏重

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

后記

花了很長時間(>10h)終于把"JS模塊化"講清楚,自己對模塊化的認識又加深了一步,事實上,理解一件事并不難,難的是如何將一件事通俗分享給別人,并讓別人也有所收獲,一直以來我也是這樣要求自己!文章如有錯誤和不正之處,歡迎指正和批評,同時也希望大家多多支持,我會有更大的創作動力!

參考文章 前端模塊化開發那點歷史 CommonJS,AMD,CMD區別 AMD 和 CMD 的區別有哪些? Javascript模塊化編程 Javascript標準參考教程 CMD 模塊定義規范 理解CommonJS、AMD、CMD三種規范

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100265.html

相關文章

  • 前端塊化詳解(整版)

    摘要:二模塊化規范概述應用由模塊組成,采用模塊規范。模塊化語法命令用于規定模塊的對外接口,命令用于輸入其他模塊提供的功能。 前言 在JavaScript發展初期就是為了實現簡單的頁面交互邏輯,寥寥數語即可;如今CPU、瀏覽器性能得到了極大的提升,很多頁面邏輯遷移到了客戶端(表單驗證等),隨著web2.0時代的到來,Ajax技術得到廣泛應用,jQuery等前端庫層出不窮,前端代碼日益膨脹,此時...

    Sanchi 評論0 收藏0
  • 【JS基礎】一文看懂前端塊化規范

    摘要:參考資料前端模塊化詳解完整版入門近一萬字的語法知識點補充徹底搞清楚中的和和詳解 前言 前端的模塊化之路經歷了漫長的過程,想詳細了解的小伙伴可以看浪里行舟大神寫的前端模塊化詳解(完整版),這里根據幾位大佬們寫的文章,將模塊化規范部分做了匯總和整理,希望讀完的小伙伴能有些收獲,也希望覺得有用的小伙伴可以點個贊,筆芯。 什么是模塊 將一個復雜的程序依據一定的規則(規范)封裝成幾個塊(文件)...

    HelKyle 評論0 收藏0
  • vue組件間通信六種方式(整版

    摘要:本文總結了組件間通信的幾種方式,如和,以通俗易懂的實例講述這其中的差別及使用場景,希望對小伙伴有些許幫助。狀態改變提交操作方法。 前言 組件是 vue.js最強大的功能之一,而組件實例的作用域是相互獨立的,這就意味著不同組件之間的數據無法相互引用。一般來說,組件可以有以下幾種關系:showImg(https://segmentfault.com/img/remote/146000001...

    frontoldman 評論0 收藏0
  • 優秀文章收藏(慢慢消化)持續更新~

    摘要:整理收藏一些優秀的文章及大佬博客留著慢慢學習原文協作規范中文技術文檔協作規范阮一峰編程風格凹凸實驗室前端代碼規范風格指南這一次,徹底弄懂執行機制一次弄懂徹底解決此類面試問題瀏覽器與的事件循環有何區別筆試題事件循環機制異步編程理解的異步 better-learning 整理收藏一些優秀的文章及大佬博客留著慢慢學習 原文:https://www.ahwgs.cn/youxiuwenzhan...

    JeOam 評論0 收藏0

發表評論

0條評論

Pines_Cheng

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<