<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # 推薦閱讀 [掘金-前端模塊化](https://juejin.im/post/5aaa37c8f265da23945f365c?utm_medium=fe&utm_source=weixinqun) [模塊化七日談](http://huangxuan.me/js-module-7day/#/6) 部分內容摘自《移動 Web 前端高效開發實踐》- iKcamp 著 # 為什么需要模塊化? JavaScript 發展初期,代碼簡單地堆積在一起,只要能順利地從上往下一次執行即可。但隨著網站越來越復雜,實現網站功能的 JavaScript 代碼也越來越龐大,網頁越來越像桌面程序,很多問題開始暴露出來,比如全局變量沖突、函數命名沖突、依賴關系處理等。 ## 1.原始的模塊化寫法 既然模塊是要實現某個功能,那么可以把實現功能的一組函數放在同一文件中,像下面這樣 ```js function a1() { // ... } function b2() { // ... } ``` 函數 a1 和 b2 組成一個模塊,其他文件先加載該模塊,再對函數進行調用。 缺點:容易發生變量命名沖突,“污染”全局變量,模塊成員之間沒有太多必然的聯系。 ## 2.添加命名空間 使用命名空間來管理模塊,即使用單全局變量的模式。 ```js var module_special = { _index: 0, a1: function () { // ...... }, b2: function () { // ...... } } // 調用 module_special.a1() module_special.b2() ``` 通常在屬性名前加下劃線表示該屬性為私有屬性,不過這只是一種開發規范上的約定,這里實際上該屬性仍然向外暴露。那么怎樣讓私有屬性不被暴露呢?那就需要下面的模塊化方式。 ## 3.立即執行函數表達式 立即執行函數表達式簡稱 “IIFE”(Immediately-Invoked Function Expression) 其能夠形成一個獨立的作用域,用 IIFE 作為一個 “容器”,“容器” 內部可以訪問外部的變量,而外部環境不能訪問 “容器” 內部的變量,所以 IIFE 內部定義的變量不會與外部的變量發生沖突。 ```js var module_special = (function () { var _index = 0 var a1 = function () { // ...... } var b2 = function () { // ...... } return { a1: a1, b2: b2 } })() // 調用 module_special.a1() module_special.b2() ``` 這種方式既避免了命名沖突,又使得私有變量 _index 不能被外部訪問和修改。jQuery 源碼大量采用了這種方式。 # CommonJS、AMD 和 CMD 規范 ## CommonJS 規范 node.js 應用由模塊組成,采用 CommonJS 規范,通過全局方法 require 來加載模塊 ``` var http = require('http') // 引入http模塊 var server = http.createServer(function (req, res) { // 用http模塊提供的方法創建一個服務 res.statusCode = 200 // 返回狀態碼為200 res.setHeader('Content-Type', 'text/plain') // 指定請求和響應的HTTP內容類型 res.end('Hello World\n') // 返回的數據 }) server.listen(3000, '127.0.0.1', function () { // 監聽的端口和主機名 console.log('Server running at http://127.0.0.1:3000') // 服務啟動成功后控制臺打印信息 }) ``` 如何編寫一個 CommonJS 規范的模塊?這就需要 Module 對象。 node.js 內部提供一個 Module 構建函數,所有模塊都是 Module 的實例。每個模塊內部,都有一個 Module 對象,代表當前模塊,包含如下屬性: - id:模塊的識別符,通常是帶有絕對路徑的模塊文件名 - filename:模塊的文件名,帶有絕對路徑 - loaded:返回一個布爾值,表示模塊是否已經完成加載 - parent:返回一個對象,表示調用該模塊 - children:返回一個數組,表示該模塊要用到的其他模塊 - exports:表示模塊對外輸出的值 其中 exports 是編寫模塊的關鍵,其表示當前模塊對外輸出的接口。其他文件加載該模塊,實際讀取的是 module.exports。 ``` // moduleA.js module.exports = function (params) { console.log(params) } // 假設兩個文件在同一目錄下 var moduleA = require('./moduleA') moduleA() // 為了方便,node.js為每個模塊提供一個exports變量指向module.exports // 那么moduleA也可以這樣編寫 exports.moduleA = function (params) { console.log(params) } ``` <span style="color: red">注意:不能把值直接賦給 exports,因為這樣等于切斷了 exports 與 module.exports 的聯系</span> 總結 CommonJS 模塊的特點如下: 1. 所有模塊都有單獨作用域,不會污染全局作用域 2. 重復加載模塊只會加載一次,后面都從緩存讀取 3. 模塊加載的順序按照代碼中出現的順序 4. 模塊加載是同步的 ## AMD 規范與 RequireJS AMD 和 CMD 規范因為現在用的比較少了(反正我是沒看見過),就簡單介紹下 CommonJS 模塊采用同步加載,適合服務端卻不適合瀏覽器。AMD 規范支持異步加載模塊,規范中定義了一個全局變量 define 函數,描述如下: `define(id?, dependencies?, factory)` 第一個參數 id,為字符串類型,表示模塊標識,為可選參數。若不存在則模塊標識默認定義為在加載器中被請求腳本的標識。如果存在,那么模塊標識必須為頂層的或者一個絕對的標識。 第二個參數 dependencies,定義當前所依賴模塊的數組。依賴模塊必須根據模塊的工廠方法優先級執行,并且執行的結果按照依賴數組中的位置順序以參數的形式傳入(定義中模塊的)工廠方法中。 第三個參數 factory,為模塊初始化時要執行的函數或對象。如果為函數,只被執行一次。如果是對象,此對象應該為模塊的輸出值。如果工廠方法返回一個值(對象、函數或任意強制類型轉換為 true 的值),應該設置為該模塊的輸出值。 創建一個標準 AMD 模塊 ``` define('alpha', ['require', 'exports', 'beta'], function (require, exports, beta) { exports.berb = function () { return beta.verb() // 或者 return require('beta').verb() } }) ``` 創建模塊標識為 “alpha” 的模塊,依賴于內置的 “require” 和 “exports” 模塊和外部標識為 “beta” 的模塊。require 函數取得模塊的引用,從而即使模塊沒有作為參數定義,也能夠被使用。exports 是定義的 alpha 模塊的實體,在其上定義的任何屬性和方法也就是 alpha 模塊的屬性和方法。 RequireJS 庫能夠把 AMD 規范應用到實際瀏覽器 Web 端的開發中,其主要解決了兩個問題:實現 JavaScript 文件的異步加載,避免網頁失去響應;管理模塊之間的依賴性,便于代碼的編寫和維護。 ``` // AMD Wrapper define( ['types/Employee'], // 依賴 function(Employee) { // 這個回調會在所有依賴都被加載后才執行 function Programmer() { // do something } Programmer.prototype = new Employee() return Programmer // return Constructor } ) ``` 我們來比較下 CommonJS 和 AMD 的書寫風格: ```js // CommonJS var a = require('./a') // 依賴就近 a.doSomething() var b = require('./b') b.doSomething() // AMD define(['a', 'b'], function (a, b) { // 依賴前置 a.doSomething() b.doSomething() }) ``` ## CMD 規范與 Sea.js CMD 規范全稱為 Common Module Definition CMD 是另一種 js 模塊化方案,它與 AMD 很類似,不同點在于:AMD 推崇依賴前置、提前執行,CMD 推崇依賴就近、延遲執行。此規范其實是在 sea.js 推廣過程中產生的。 ``` /** AMD寫法 **/ define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { // 等于在最前面聲明并初始化了要用到的所有模塊 a.doSomething(); if (false) { // 即便沒用到某個模塊 b,但 b 還是提前執行了 b.doSomething() } }); /** CMD寫法 **/ define(function(require, exports, module) { var a = require('./a'); //在需要時申明 a.doSomething(); if (false) { var b = require('./b'); b.doSomething(); } }); /** sea.js **/ // 定義模塊 math.js define(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); }); ``` # ECMAScript6 標準的模塊支持 ECMAScript5 及之前的版本不支持原生模塊化,需要引入 AMD 規范的 RequireJS 或者 AMD 規范的 Seajs 等第三方庫來實現。 直到 ECMAScript6 才支持原生模塊化,其不但具有 CommonJS 規范和 AMD 規范的優點,而且實現得更加友好,語法較之 CommonJS 更簡潔、支持編譯時加載(靜態加載),循環依賴處理得更好。 ES6 模塊功能主要由兩個命令構成:export 和 import,export 命令用于規定模塊的對外接口,import 命令用于輸入其他模塊提供的功能。 ## export 在 ES6 中,一個模塊也是一個獨立的文件,具有獨立的作用域,通過 export 命令輸出內部變量 ```js let name = 'bus' let color = 'green' let weight = '20噸噸噸' export {name, color, weight} // export命令除了輸出變量,還可以輸出函數或類 export function run() { console.log('Bus is running') } ``` ```js // 可以使用 as 關鍵字對輸出的變量、函數、類重命名 let name = 'bus' let color = 'green' let weight = '20噸噸噸' function run() { console.log('Bus is running') } export { name as busName, color as busColor, weight as busWeight, run as busRun } ``` ## import import 命令用于導入模塊 ``` import { name, color, weight, run } from './car' // 導入一個模塊的時候也可以用 as 關鍵字對模塊進行重命名 import {name as busName } from './car' // 通過星號 '*' 整體加載某個文件 import * as car from './car' console.log(car.name) // bus console.log(car.color) // green ``` ## export default 命令 從前面的例子可以看出,使用 import 命令加載模塊時需要知道變量名或者函數名,或者整個文件,否則無法加載。為了方便,可以使用 export default 命令為模塊指定默認輸出,加載該模塊時,可以使用 import 命令為其指定任意名字。 ``` // 定義模塊 math.js let basicNum = 0 let add = function(a, b) { return a+b } export default { basicNum, add } // 引入 import math from './math' function test() { console.log(math.add(99 + math.basicNum)) } ``` > 附:阮一峰《ES6標準入門》 > import 命令是靜態加載而不是動態加載的,如果 import 命令要取代 require 方法,就要能實現動態加載。 > 有一個提案:建議引入 import() 函數,完成動態加載,import 命令能夠接收什么參數,import() 函數命令就能接受什么參數。 關于上面所說的提案,現在配置 webpack 使用 babel 轉譯應該能實現了(Vue 的路由懶加載,Webpack 的 splitChunk 都有用到)。 現在前端框架基本上使用 ES6 的模塊化語法,node.js 仍然保持 require 導入,兩者最主要的區別是: - require 是運行時加載,import 是編譯時加載 即下面的條件加載是不可能實現的 ``` if (x === 2) { import MyModual from './myModual' } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看