前端模塊化詳解

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

本文內(nèi)容主要有理解模塊化,為什么要模塊化霎迫,模塊化的優(yōu)缺點以及模塊化規(guī)范, 并且介紹下開發(fā)中最流行的 CommonJS斋枢、AMD、 ES6知给、CMD 規(guī)范瓤帚。本文試圖站在小白的角度,用通俗易懂的筆調(diào)介紹這些枯燥無味的概念,希望諸君閱讀后缘滥,對模塊化編程有個全新的認識和理解轰胁!
一、模塊化的理解1. 什么是模塊?

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

2. 模塊化的進化過程

全局 function 模式:將不同的功能封裝成不同的全局函數(shù)榛斯;

編碼: 將不同的功能封裝成不同的全局函數(shù);

問題: 污染全局命名空間搂捧,容易引起命名沖突或數(shù)據(jù)不安全驮俗,而且模塊成員之間看不出直接關(guān)系。

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

namespace 模式:簡單對象封裝

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

  • 問題: 數(shù)據(jù)不安全 (外部可以直接修改模塊內(nèi)部的數(shù)據(jù))

  • let myModule = { data: 'www.baidu.com', foo() {   console.log(`foo() ${this.data}`) }, bar() {   console.log(`bar() ${this.data}`) }}myModule.data = 'other data' // 能直接修改模塊內(nèi)部的數(shù)據(jù)myModule.foo() // foo() other data
    

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

IIFE 模式:匿名函數(shù)自調(diào)用 (閉包)

  • 作用: 數(shù)據(jù)是私有的聋丝, 外部只能通過暴露的方法操作索烹;

  • 編碼: 將數(shù)據(jù)和行為封裝到一個函數(shù)內(nèi)部, 通過給 window 添加屬性來向外暴露接口;

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

// index.html 文件<script type="text/javascript" src="module.js"></script><script type="text/javascript">   myModule.foo()   myModule.bar()   console.log(myModule.data) //undefined 不能訪問模塊內(nèi)部數(shù)據(jù)   myModule.data = 'xxxx' // 不是修改的模塊內(nèi)部的 data   myModule.foo() // 沒有改變</script>
// module.js 文件(function(window) { let data = 'www.baidu.com' // 操作數(shù)據(jù)的函數(shù) function foo() {   // 用于暴露有函數(shù)   console.log(`foo() ${data}`) } function bar() {   // 用于暴露有函數(shù)   console.log(`bar() ${data}`)   otherFun() // 內(nèi)部調(diào)用 } function otherFun() {   // 內(nèi)部私有的函數(shù)   console.log('otherFun()') } // 暴露行為 window.myModule = { foo, bar } //ES6 寫法})(window)

最后得到的結(jié)果:

image

IIFE 模式增強:引入依賴

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

// module.js 文件(function(window, $) { let data = 'www.baidu.com' // 操作數(shù)據(jù)的函數(shù) function foo() {   // 用于暴露有函數(shù)   console.log(`foo() ${data}`)   $('body').css('background', 'red') } function bar() {   // 用于暴露有函數(shù)   console.log(`bar() ${data}`)   otherFun() // 內(nèi)部調(diào)用 } function otherFun() {   // 內(nèi)部私有的函數(shù)   console.log('otherFun()') } // 暴露行為 window.myModule = { foo, bar }})(window, jQuery)
// index.html 文件 <!-- 引入的 js 必須有一定順序 --> <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>

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

3. 模塊化的好處

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

  • 更好的分離, 按需加載

  • 更高復(fù)用性

  • 高可維護性

4. 引入多個<script>后出現(xiàn)出現(xiàn)問題

  • 請求過多

首先我們要依賴多個模塊火惊,那樣就會發(fā)送多個請求求类,導(dǎo)致請求過多。

  • 依賴模糊

我們不知道他們的具體依賴關(guān)系是什么尸疆,也就是說很容易因為不了解他們之間的依賴關(guān)系導(dǎo)致加載先后順序出錯张症。

  • 難以維護

以上兩種原因就導(dǎo)致了很難維護鸵贬,很可能出現(xiàn)牽一發(fā)而動全身的情況導(dǎo)致項目出現(xiàn)嚴重的問題俗他。模塊化固然有多個好處阔逼,然而一個頁面需要引入多個 js 文件,就會出現(xiàn)以上這些問題。而這些問題可以通過模塊化規(guī)范來解決羡亩,下面介紹開發(fā)中最流行的 commonjs摩疑、AMD、ES6雷袋、CMD 規(guī)范楷怒。

二瓦灶、模塊化規(guī)范1.CommonJS (1) 概述

Node 應(yīng)用由模塊組成,采用 CommonJS 模塊規(guī)范刃泡。每個文件就是一個模塊碉怔,有自己的作用域眨层。在一個文件里面定義的變量、函數(shù)馒闷、類纳账,都是私有的捺疼,對其他文件不可見啤呼。在服務(wù)器端,模塊的加載是運行時同步加載的翅敌;在瀏覽器端惕蹄,模塊需要提前編譯打包處理。

(2) 特點

所有代碼都運行在模塊作用域张峰,不會污染全局作用域词顾。

模塊可以多次加載粘衬,但是只會在第一次加載時運行一次科盛,然后運行結(jié)果就被緩存了甜孤,以后再加載橘券,就直接讀取緩存結(jié)果旁舰。要想讓模塊再次運行箭窜,必須清除緩存纳猫。

模塊加載的順序,按照其在代碼中出現(xiàn)的順序侵续。

(3) 基本語法

  • 暴露模塊:module.exports = valueexports.xxx = value

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

此處我們有個疑問:CommonJS 暴露的模塊到底是什么? CommonJS 規(guī)范規(guī)定渔呵,每個模塊內(nèi)部,module 變量代表當前模塊录豺。這個變量是一個對象双饥,它的 exports 屬性(即 module.exports)是對外的接口弟断。加載某個模塊阀趴,其實是加載該模塊的 module.exports 屬性舍咖。

// example.jsvar x = 5;var addX = function (value) { return value + x;};module.exports.x = x;module.exports.addX = addX;

上面代碼通過 module.exports 輸出變量 x 和函數(shù) addX。

var example = require('./example.js');// 如果參數(shù)字符串以“./”開頭窍株,則表示加載的是一個位于相對路徑console.log(example.x); // 5console.log(example.addX(1)); // 6

(4) 模塊的加載機制

CommonJS 模塊的加載機制是球订,輸入的是被輸出的值的拷貝瑰钮。也就是說浪谴,一旦輸出一個值,模塊內(nèi)部的變化就影響不到這個值篇恒。這點與 ES6 模塊化有重大差異(下文會介紹)胁艰,請看下面這個例子:

// lib.jsvar counter = 3;function incCounter() { counter++;}module.exports = { counter: counter, incCounter: incCounter,};

上面代碼輸出內(nèi)部變量 counter 和改寫這個變量的內(nèi)部方法 incCounter腾么。

// main.jsvar counter = require('./lib').counter;var incCounter = require('./lib').incCounter;console.log(counter);  // 3incCounter();console.log(counter); // 3

上面代碼說明,counter 輸出以后攘须,lib.js 模塊內(nèi)部的變化就影響不到 counter 了阻课。這是因為 counter 是一個原始類型的值限煞,會被緩存员凝。除非寫成一個函數(shù)健霹,才能得到內(nèi)部變動后的值。

(5) 服務(wù)器端實現(xiàn)

①下載安裝 node.js

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

注意:用 npm init 自動生成 package.json 時宣吱,package name(包名) 不能有中文和大寫:

|-modules |-module1.js |-module2.js |-module3.js|-app.js|-package.json {   "name": "commonJS-node",   "version": "1.0.0" }

③下載第三方模塊

npm install uniq --save // 用于數(shù)組去重征候;

④定義模塊代碼

//module1.jsmodule.exports = { msg: 'module1', foo() {   console.log(this.msg) }}
//module2.jsmodule.exports = function() { console.log('module2')}
//module3.jsexports.foo = function() { console.log('foo() module3')}exports.arr = [1, 2, 3, 3, 2]
// 引入第三方庫疤坝,應(yīng)該放置在最前面let uniq = require('uniq')let module1 = require('./modules/module1')let module2 = require('./modules/module2')let module3 = require('./modules/module3')module1.foo() //module1module2() //module2module3.foo() //foo() module3console.log(uniq(module3.arr)) //[ 1, 2, 3 ]

⑤通過 node 運行 app.js

命令行輸入 node app.js跑揉,運行 JS 文件。

(6) 瀏覽器端實現(xiàn) (借助 Browserify)

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

|-js |-dist // 打包生成文件的目錄 |-src // 源碼所在的目錄   |-module1.js   |-module2.js   |-module3.js   |-app.js // 應(yīng)用主源文件|-index.html // 運行于瀏覽器上|-package.json {   "name": "browserify-test",   "version": "1.0.0" }

②下載 browserify

  • 全局: npm install browserify -g

  • 局部: npm install browserify --save-dev

③定義模塊代碼 (同服務(wù)器端)

注意:index.html 文件要運行在瀏覽器上现拒,需要借助 browserify 將 app.js 文件打包編譯具练,如果直接在 index.html 引入 app.js 就會報錯!

④打包處理 js

根目錄下運行 browserify js/src/app.js -o js/dist/bundle.js

⑤頁面使用引入

在 index.html 文件中引入< script type="text/javascript" src="js/dist/bundle.js">

2. AMD

CommonJS 規(guī)范加載模塊是同步的岂丘,也就是說奥帘,只有加載完成仪召,才能執(zhí)行后面的操作扔茅。AMD 規(guī)范則是非同步加載模塊,允許指定回調(diào)函數(shù)运褪。

由于 Node.js 主要用于服務(wù)器編程秸讹,模塊文件一般都已經(jīng)存在于本地硬盤璃诀,所以加載起來比較快蔑匣,不用考慮非同步加載的方式裁良,所以 CommonJS 規(guī)范比較適用趴久。但是,如果是瀏覽器環(huán)境灭忠,要從服務(wù)器端加載模塊弛作,這時就必須采用非同步模式映琳,因此瀏覽器端一般采用 AMD 規(guī)范。此外 AMD 規(guī)范比 CommonJS 規(guī)范在瀏覽器端實現(xiàn)要來著早有鹿。

(1) AMD 規(guī)范基本語法

定義暴露模塊:

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

引入使用模塊:

引入使用模塊:require(['module1', 'module2'], function(m1, m2){  使用 m1/m2})

(2) 未使用 AMD 規(guī)范與使用 require.js

通過比較兩者的實現(xiàn)方法葱跋,來說明使用 AMD 規(guī)范的好處娱俺。

未使用 AMD 規(guī)范

// 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 文件<div><h1>Modular Demo 1: 未使用 AMD(require.js)</h1></div><script type="text/javascript" src="js/modules/dataService.js"></script><script type="text/javascript" src="js/modules/alerter.js"></script><script type="text/javascript" src="js/main.js"></script>

最后得到如下結(jié)果:

image.gif

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

使用 require.js

RequireJS 是一個工具庫社牲,主要用于客戶端的模塊管理搏恤。它的模塊管理遵守 AMD 規(guī)范,RequireJS 的基本思想是藤巢,通過 define 方法掂咒,將代碼定義為模塊绍刮;通過 require 方法,實現(xiàn)代碼的模塊加載岁歉。

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

①下載 require.js锅移,并引入

官網(wǎng): http://www.requirejs.cn/

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

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

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

|-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/', // 基本路徑 出發(fā)點在根目錄下   paths: {     // 映射: 模塊標識名: 路徑     alerter: './modules/alerter', // 此處不能寫成 alerter.js, 會報錯     dataService: './modules/dataService'   } }) require(['alerter'], function(alerter) {   alerter.showMsg() })})()
// index.html 文件<!DOCTYPE html><html> <head>   <title>Modular Demo</title> </head> <body>   <!-- 引入 require.js 并指定 js 主文件的入口 -->   <script data-main="js/main" src="js/libs/require.js"></script> </body></html>

④ 頁面引入 require.js 模塊:

在 index.html 引入 < script data-main="js/main" src="js/libs/require.js">< /script>

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

// 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/', // 基本路徑 出發(fā)點在根目錄下   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 文件也要有相應(yīng)的路徑配置坤学。

小結(jié):通過兩者的比較深浮,可以得出 AMD 模塊定義的方法非常清晰飞苇,不會污染全局環(huán)境蜗顽,能夠清楚地顯示依賴關(guān)系雇盖。AMD 模式可以用于瀏覽器環(huán)境崔挖,并且允許非同步加載模塊,也可以根據(jù)需要動態(tài)加載模塊薛匪。

3.CMD

CMD 規(guī)范專門用于瀏覽器端逸尖,模塊的加載是異步的冷溶,模塊使用時才會加載執(zhí)行。CMD 規(guī)范整合了 CommonJS 和 AMD 規(guī)范的特點纯衍。在 Sea.js 中襟诸,所有 JavaScript 模塊都遵循 CMD 模塊定義規(guī)范歌亲。

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

定義暴露模塊:

// 定義沒有依賴的模塊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, 并引入

官網(wǎng): http://seajs.org/

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

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

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

|-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) { // 內(nèi)部變量數(shù)據(jù) var data = 'atguigu.com' // 內(nèi)部函數(shù) 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 中引入

<script type="text/javascript" src="js/libs/sea.js"></script><script type="text/javascript"> seajs.use('./js/modules/main')</script>

最后得到結(jié)果如下:

image

4.ES6 模塊化

ES6 模塊的設(shè)計思想是盡量的靜態(tài)化杂穷,使得編譯時就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量飞蚓。CommonJS 和 AMD 模塊趴拧,都只能在運行時確定這些東西著榴。比如屁倔,CommonJS 模塊就是對象汰现,輸入時必須查找對象屬性瞎饲。

(1) ES6 模塊化語法

export 命令用于規(guī)定模塊的對外接口嗅战,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 命令的時候本讥,用戶需要知道所要加載的變量名或函數(shù)名拷沸,否則無法加載撞芍。為了給用戶提供方便跨扮,讓他們不用閱讀文檔就能加載模塊衡创,就要用到 export default 命令钧汹,為模塊指定默認輸出拔莱。

// export-default.jsexport default function () { console.log('foo');}
// import-default.jsimport customName from './export-default';customName(); // 'foo'

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

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

它們有兩個重大差異:

① CommonJS 模塊輸出的是一個值的拷貝菱皆,ES6 模塊輸出的是值的引用仇轻。

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

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

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

// lib.jsexport let counter = 3;export function incCounter() { counter++;}// main.jsimport { counter, incCounter } from './lib';console.log(counter); // 3incCounter();console.log(counter); // 4

ES6 模塊的運行機制與 CommonJS 不一樣穗慕。ES6 模塊是動態(tài)引用逛绵,并且不會緩存值,模塊里面的變量綁定其所在的模塊瓢对。

(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 預(yù)設(shè) (將 es6 轉(zhuǎn)換成 es5 的所有插件打包)

③ 定義.babelrc 文件

{   "presets": ["es2015"] }

④ 定義模塊代碼

//module1.js 文件// 分別暴露export function foo() { console.log('foo() module1')}export function bar() { console.log('bar() module1')}
//module2.js 文件// 統(tǒng)一暴露function fun1() { console.log('fun1() module2')}function fun2() { console.log('fun2() module2')}export { fun1, fun2 }
//module3.js 文件// 默認暴露 可以暴露任意數(shù)據(jù)類項埃仪,暴露什么數(shù)據(jù),接收到就是什么數(shù)據(jù)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 文件中引入:

<script type="text/javascript" src="js/lib/bundle.js"></script>

最后得到如下結(jié)果:

image

此外第三方庫 (以 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')

三琉兜、總結(jié)

CommonJS 規(guī)范主要用于服務(wù)端編程,加載模塊是同步的毙玻,這并不適合在瀏覽器環(huán)境豌蟋,因為同步意味著阻塞加載,瀏覽器資源是異步加載的桑滩,因此有了 AMD CMD 解決方案。

AMD 規(guī)范在瀏覽器環(huán)境中異步加載模塊运准,而且可以并行加載多個模塊幌氮。不過,AMD 規(guī)范開發(fā)成本高胁澳,代碼的閱讀和書寫比較困難该互,模塊定義方式的語義不順暢。

CMD 規(guī)范與 AMD 規(guī)范很相似韭畸,都用于瀏覽器編程宇智,依賴就近,延遲執(zhí)行胰丁,可以很容易在 Node.js 中運行随橘。不過,依賴 SPM 打包锦庸,模塊的加載邏輯偏重ES6 在語言標準的層面上机蔗,實現(xiàn)了模塊功能,而且實現(xiàn)得相當簡單甘萧,完全可以取代 CommonJS 和 AMD 規(guī)范萝嘁,成為瀏覽器和服務(wù)器通用的模塊解決方案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末幔嗦,一起剝皮案震驚了整個濱河市酿愧,隨后出現(xiàn)的幾起案子沥潭,更是在濱河造成了極大的恐慌邀泉,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钝鸽,死亡現(xiàn)場離奇詭異汇恤,居然都是意外死亡,警方通過查閱死者的電腦和手機拔恰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門因谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颜懊,你說我怎么就攤上這事财岔》缑螅” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵匠璧,是天一觀的道長桐款。 經(jīng)常有香客問我,道長夷恍,這世上最難降的妖魔是什么魔眨? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮酿雪,結(jié)果婚禮上遏暴,老公的妹妹穿的比我還像新娘。我一直安慰自己指黎,他們只是感情好朋凉,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著醋安,像睡著了一般侥啤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茬故,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天盖灸,我揣著相機與錄音,去河邊找鬼磺芭。 笑死赁炎,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的钾腺。 我是一名探鬼主播徙垫,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼放棒!你這毒婦竟也來了姻报?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤间螟,失蹤者是張志新(化名)和其女友劉穎吴旋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厢破,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡荣瑟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了摩泪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笆焰。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖见坑,靈堂內(nèi)的尸體忽然破棺而出嚷掠,到底是詐尸還是另有隱情捏检,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布不皆,位于F島的核電站未檩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏粟焊。R本人自食惡果不足惜冤狡,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望项棠。 院中可真熱鬧悲雳,春花似錦、人聲如沸香追。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽透典。三九已至晴楔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間峭咒,已是汗流浹背税弃。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凑队,地道東北人则果。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像漩氨,于是被迫代替她去往敵國和親西壮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容