模塊化

主要解決

避免全局污染较性,解決命名沖突

JS設(shè)計初衷

JS誕生的時候呵晚,僅僅是為了實現(xiàn)網(wǎng)頁表單的本地校驗和簡單的DOM操作瘩欺,并沒有模塊化的規(guī)范設(shè)計

隨著前端越來越豐富必盖,一些問題隨之而來拌牲,于是模塊化才漸漸的趨于規(guī)范化

原始JS命名沖突

張三寫了一個腳本tab.js,李四寫了一個腳本index.js歌粥,如果命名有沖突塌忽,就會相互覆蓋

// 張三
var name = "產(chǎn)品";
// 李四
var name = "首頁";

前綴是之前變量沖突很好的解決方案,但是缺點一是命名不規(guī)范失驶,缺點二是有些人的名稱簡寫相同

// 張三
var zs_name = "產(chǎn)品";
// 李四
var ls_name = "首頁";

這時候土居,模塊化的思想就漸漸開始形成,比如模塊化演變一:命名空間

var tab = {
    name:"產(chǎn)品"
}
var index = {
    name:"首頁"
}

模塊化演變二:局部作用域

function tab () {
    var name = "產(chǎn)品";
}
function index () {
    var name = "首頁";
}

模塊化演變?nèi)鹤詧?zhí)行函數(shù)(已很好的隔離作用域嬉探,很多非標(biāo)準(zhǔn)模塊化的插件擦耀,腳本都是以這種形式書寫)

;(function () {
    var name = "產(chǎn)品";
})();

;(function () {
    var name = "首頁";
})();

最終演變

模塊化演變到現(xiàn)在出現(xiàn)了AMD,CMD涩堤,CommonJS(node方案)等模塊化標(biāo)準(zhǔn)眷蜓,然后前端模塊化進入大爆發(fā)時代,未來的趨勢肯定是ES6的標(biāo)準(zhǔn)方案會逐漸統(tǒng)一胎围,但是AMD吁系,CMD、CommonJS和ES6的的標(biāo)準(zhǔn)方案相差不大

AMD標(biāo)準(zhǔn)

中文API地址https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)

模塊化逐步演變的過程中痊远,AMD規(guī)范一直站前端主導(dǎo)地位垮抗,出現(xiàn)了很多實現(xiàn)AMD規(guī)范的插件,現(xiàn)在以requireJS(https://requirejs.org/)為例

requireJS出了個rJS專門針對nodeJS的模塊化標(biāo)準(zhǔn)碧聪,但是一般不會使用

hello

在html頁面中引入

<!-- src是為了引入腳本冒版,data-main設(shè)置入口文件 -->
<script src="./lib/require2.3.6.min.js" data-main="lib/main"></script>

lib/main.js

require(["moduleA", "moduleB"], function (moduleA, moduleB) {
    console.log(moduleA);
    console.log(moduleB);
})

lib/moduleA.js

define(() => ({
    name: "產(chǎn)品"
}));

lib/moduleB.js

define(() => ({
    name: "首頁"
}));

源碼解析(非完全)

執(zhí)行require函數(shù)時,得到模塊的相對路徑逞姿,生成script腳本辞嗡,比如:<script async src="加載的模塊地址"></script>,并添加到head標(biāo)簽中滞造,添加偵聽腳本加載完成事件

// 源碼截取
req.createNode = function (config, moduleName, url) {
    var node = config.xhtml ?
        document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
        document.createElement('script');
    node.type = config.scriptType || 'text/javascript';
    node.charset = 'utf-8';
    node.async = true;
    return node;
};

運行動態(tài)添加的腳本語言续室,執(zhí)行模塊的define函數(shù),參數(shù)push到全局隊列

// 源碼截取
define = function (name, deps, callback) {
    // 很多省略代碼
    if (context) {
        context.defQueue.push([name, deps, callback]);
        context.defQueueMap[name] = true;
    } else {
        globalDefQueue.push([name, deps, callback]);
    }
};

執(zhí)行require的回調(diào)函數(shù)谒养,取出隊列作為參數(shù)

define函數(shù)的參數(shù)

語法:\color{red}{define(name?:string, dependencies?:string [], callback)}

name:模塊名稱挺狰,如果沒有命名則為引入腳本的名字。如果寫了name买窟,模塊名必須是頂級的和絕對的(不允許用相對名字)

dependencies:依賴項

callback:回調(diào)函數(shù)丰泊,返回模塊內(nèi)容

define有amd屬性, 它的值是一個對象始绍,這是為了規(guī)范編程規(guī)則瞳购,可以防止與現(xiàn)有定義了define函數(shù)但不遵從AMD編程接口的代碼相沖突

define.amd = {
    jQuery: true
};

怎么判斷一個庫支不支持Amd標(biāo)準(zhǔn),判斷define是全局函數(shù)亏推,且define有amd屬性学赛,比如jquery

if (typeof define === "function" && define.amd) {
    define("jquery", [], function () {
        return jQuery;
    });
}

define可以引入依賴模塊年堆,依賴模塊的地址可以用require.config進行路徑映射(見下)

define(['jquery'], function ($) {
    'use strict';
    $.get("/user/info", (res) => {
        console.log(res);
    })
});

define的標(biāo)準(zhǔn)寫法是使用exports一個對象作為返回對象,如果沒有exports盏浇,會以函數(shù)的返回值作為返回對象

define("moduleA", ["exports"], (exports) => {
    exports.moduleA = { name: "產(chǎn)品" }
})

使用exports導(dǎo)出的對象的格式變?yōu)閧 moduleA: {name: "產(chǎn)品"} }变丧,而不是{name: "產(chǎn)品"},如果想實現(xiàn)return效果可以使用解構(gòu)

require(["moduleA", "moduleB"], function ({ moduleA }, moduleB) {
    console.log(moduleA);
    console.log(moduleB);
})

defined還有一種寫法,引入require模塊后绢掰,使用require引入其他模塊锄贷。依賴模塊非常多時,這種寫法比較簡潔

define("moduleA", ["require", "jquery"], (require) => {
    let $ = require("jquery");
    console.log($.fn);
    return { name: "產(chǎn)品" };
})
require函數(shù)

require可以有一個config屬性曼月,可以配置模塊路徑

require.config({
    paths: {
        jquery: "../lib/jquery.js"
    }
});

CMD標(biāo)準(zhǔn)

sea.js(國產(chǎn))在推廣過程中,逐漸形成了CMD規(guī)范柔昼,跟AMD比較類似哑芹,并且兼容CommonJS的模塊寫法,但是目前已不再維護

CMD推崇的是就近依賴捕透,AMD則默認(rèn)約束模塊一開始就聲明相關(guān)依賴聪姿,其他定義方式及模塊相關(guān)變量都很相似

CMD寫法

define((require, exports, module) => {
    // 模塊代碼
})

CommonJS標(biāo)準(zhǔn)

這是nodeJS的模塊化標(biāo)準(zhǔn),致力于前后端統(tǒng)一的模塊化標(biāo)準(zhǔn)乙嘀,差點統(tǒng)一模塊化天下

模塊寫法

module.exports = {
    name: "首頁"
}

在CommonJS規(guī)范中末购,module.exports和exports相等,所以module.exports可以簡寫為exports

exports = {
    name: "首頁"
}

模塊引入虎谢,不加后綴表示js文件(注意盟榴,CMD和AMD如果和入口文件在同一目錄下,可以省略./婴噩,但是CommonJS不行)

let moduleA = require("./moduleA");

console.log(moduleA);

模塊引入可解構(gòu)

let { name } = require("./moduleA");

console.log(name);

可引入內(nèi)置文件(Node自帶功能)

const path = require("path");

引入node_modules文件夾的內(nèi)容擎场,也可以直接寫名稱,比如:cnpm i jquery几莽,則引入時迅办,可以用以下方式

 const jquery = require("jquery");

ES6模塊化標(biāo)準(zhǔn)

未來模塊化的一統(tǒng)標(biāo)準(zhǔn)

定義模塊

模塊寫法一

export var a = 10;
export var f = function () {
    console.log(1);
}

模塊寫法二

var a = 10;
var f = function () {
    console.log(1);
}

export { a, f }

模塊寫法三(export default一個頁面只有有一個,export可以有多個章蚣,可共存)

export default {
    name: "首頁"
}

模塊寫法可以使用別名

function v1() { }
function v2() { }

export {
    v1 as streamV1,
    v2 as streamV2
}
引入模塊

假如有如下定義模塊

let name = "首頁";
let version = "2.0.7";

export {
    name, version
}

export default {
    name, version
}

引入處理

使用export導(dǎo)出的模塊站欺,必須用import并用{ }來接收

export default導(dǎo)出,比如用一個對象接收纤垂,且不支持解構(gòu)

import { name, version } from "./moduleA"
import info from "./moduleA"

默認(rèn)export導(dǎo)出的內(nèi)容無法用對象接收矾策,export default導(dǎo)出的內(nèi)容無法解構(gòu),如果希望export導(dǎo)出的內(nèi)容也能用對象接收洒忧,可以用關(guān)鍵字as申明別名

// 聲明
let name = "首頁";
let version = "2.0.7";

export {
    name, version
}

// 接收
import * as info from "./moduleA"
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝴韭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子熙侍,更是在濱河造成了極大的恐慌榄鉴,老刑警劉巖履磨,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異庆尘,居然都是意外死亡剃诅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門驶忌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矛辕,“玉大人,你說我怎么就攤上這事付魔×钠罚” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵几苍,是天一觀的道長翻屈。 經(jīng)常有香客問我,道長妻坝,這世上最難降的妖魔是什么伸眶? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮刽宪,結(jié)果婚禮上厘贼,老公的妹妹穿的比我還像新娘。我一直安慰自己圣拄,他們只是感情好嘴秸,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著售担,像睡著了一般赁遗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上族铆,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天岩四,我揣著相機與錄音,去河邊找鬼哥攘。 笑死剖煌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逝淹。 我是一名探鬼主播耕姊,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼栅葡!你這毒婦竟也來了茉兰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤欣簇,失蹤者是張志新(化名)和其女友劉穎规脸,沒想到半個月后坯约,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡莫鸭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年闹丐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片被因。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡卿拴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梨与,到底是詐尸還是另有隱情堕花,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布粥鞋,位于F島的核電站航徙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陷虎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一杠袱、第九天 我趴在偏房一處隱蔽的房頂上張望尚猿。 院中可真熱鬧,春花似錦楣富、人聲如沸凿掂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庄萎。三九已至,卻和暖如春塘安,著一層夾襖步出監(jiān)牢的瞬間糠涛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工兼犯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留忍捡,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓切黔,卻偏偏與公主長得像砸脊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纬霞,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354