JavaScript中Require調(diào)用js的實(shí)例分享
在我最初開始寫 JavaScript 函數(shù)時(shí),通常是這樣的:
function fun1() { // some code here } function fun2() { // some other code here } ...
函數(shù)全寫在全局環(huán)境中,項(xiàng)目很小時(shí),通常不會(huì)有什么沖突問題。
但代碼多了后,漸漸就發(fā)現(xiàn),函數(shù)名稱(英文詞匯)有點(diǎn)不夠用了。于是引入命名空間的概念,開始模塊化代碼。
命名空間下的函數(shù)
在命名空間下,我的代碼這樣寫:
var com = com || {}; com.zfanw = com.zfanw || {}; com.zfanw.module1 = (function() { // some code here return { func1: func1, ... }; }()); com.zfanw.module2 = (function() { // some other code here return { func1: func1, ... }; }()); ...
本著要面向?qū)ο蟮脑瓌t,執(zhí)行函數(shù)通常我要這么寫的:
com.zfanw.module1.func1.apply({},['arg1',arg2]); ...
當(dāng)然,為了少打些字符,我還會(huì)在閉包中導(dǎo)入1公共 API 接口:www.dbjr.com.cn
(function($, mod1) { // some code here mod1.func1.apply({},['arg1',arg2]); }(jQuery, com.zfanw.module1)); ...
至此,代碼沖突的可能性已經(jīng)很小,但代碼依賴的問題,多腳本文件管理、阻塞的問題,漸漸浮出水面 – 命名空間的辦法開始捉急。
于是 Require.js2 出場。
Require.js
首先了解下 require.js 里模塊的概念3:
A module is different from a traditional script file in that it defines a well-scoped object that avoids polluting the global namespace. It can explicitly list its dependencies and get a handle on those dependencies without needing to refer to global objects, but instead receive the dependencies as arguments to the function that defines the module.
簡單地說,有兩點(diǎn),一、模塊作用域自成一體,不污染全局空間;二、模塊指明依賴關(guān)系,并且依賴是通過參數(shù)傳遞的形式導(dǎo)入的,無需通過全局對(duì)象引用 – 依賴同樣不污染全局空間。
定義模塊
與上面的老長的命名空間方式不同,require.js 用全局方法 define 來定義模塊,形式如下:
define(id?, dependencies?, factory); // ? 表示可選項(xiàng)
我且把模塊分兩種。
無依賴的模塊
假如一個(gè)模塊并不依賴其他模塊,那么定義起來是很簡單的,比如模塊 hello 放在 hello.js 文件中:
define(function() { // some code here return { // some public api }; });
有依賴的模塊
有依賴的模塊要稍稍復(fù)雜點(diǎn),define 時(shí),我們需要羅列出模塊的依賴情況:
define(['jquery'], function($) { // 比如這個(gè)模塊,代碼的執(zhí)行依賴 jQuery,require.js 會(huì)先加載 jquery 模塊代碼,并加以執(zhí)行,然后將依賴模塊 以 $ 的參數(shù)形式傳入回調(diào)函數(shù)中,回調(diào)函數(shù)將執(zhí)行結(jié)果注冊(cè)為模塊 // maybe some code here return { // some public api }; });
這里,依賴中的 'jquery' 是模塊相對(duì)于 baseUrl 的路徑,等效于模塊 ID。
現(xiàn)在,再回過頭,看看上面寫過的閉包中導(dǎo)入公共 API 的代碼,跟 define 函數(shù)做個(gè)對(duì)比:
(function($, mod1) { // some code here mod1.func1.apply({},['arg1',arg2]); }(jQuery, com.zfanw.module1));
這段代碼里,我同樣把 jQuery 導(dǎo)入了,在閉包里,我同樣是通過 $ 這個(gè)外部傳入的參數(shù)來訪問 jQuery。可以說,它「定義依賴」的方式跟 define 方法很相似,不同的是,define 導(dǎo)入的 jquery 不是全局變量,所以不會(huì)污染全局環(huán)境。
關(guān)于模塊名稱
define 函數(shù)有三個(gè)參數(shù),第一個(gè) id 即模塊名稱,這個(gè)名稱的格式是相對(duì)于 baseUrl 的路徑除去文件格式,比如 baseUrl 為 js 目錄,一個(gè)模塊放在 js/libs/hi.js 里,則如果名稱是這樣定義的:
define('libs/hi', ['jquery'], function($){......});
這樣的定義形式的好處是,模塊不可能沖突,因?yàn)橥荒夸浵虏辉试S同名文件。但也因此 require.js 建議我們不要設(shè)置模塊名稱,因?yàn)樵O(shè)置了 ‘libs/hi' 的模塊名稱后,模塊就必須放在 js/libs 目錄下的 hi.js 文件中,要移動(dòng)位置的話,模塊名稱要跟著改變。至于后期利用 r.js 優(yōu)化時(shí)生成了模塊名稱,那已經(jīng)是另外一回事。
使用模塊
在定義好「有依賴」、「沒依賴」的各種模塊后,我們?cè)撛趺从盟縍equire.js 提供了一個(gè)函數(shù),require(與 requirejs 等效)。
require 函數(shù)加載依賴并執(zhí)行回調(diào),與 define 不同的是,它不會(huì)把回調(diào)結(jié)果4注冊(cè)成模塊:
require(['jquery'], function($) { // 這個(gè)函數(shù)加載 jquery 依賴,然后執(zhí)行回調(diào)代碼 console.log($); });
舉一個(gè)簡單的例子。我有一個(gè)文件夾,文件結(jié)構(gòu)如下:
index.html js/ main.js require.js jquery.js
這里 jquery.js 已經(jīng)注冊(cè)為 AMD 模塊,則 HTML 文件里這樣引用 require.js:
<script src="js/require.js" data-main="js/main"></script>
require.js 會(huì)檢查 data-main 屬性值,這里是 js/main,根據(jù)設(shè)定,它會(huì)加載 js 目錄下的 main.js 文件。
main.js 文件里,我只干一件事,用 jQuery 方法取得當(dāng)前窗口的寬度:
require(['jquery'], function($) { var w = $(window).width(); console.log(w); });
執(zhí)行代碼就這么簡單。
非 AMD 規(guī)范的模塊
但事情遠(yuǎn)沒有我們想像中那么美好,AMD 只是一種社區(qū)規(guī)范,并非標(biāo)準(zhǔn),而且在它出現(xiàn)以前,已經(jīng)有各種各樣的流行庫存在,更不用說我們自己早期寫的代碼,所以我們一定會(huì)碰上一堆非 AMD 規(guī)范的模塊。為了讓 require.js 能夠加載它們,并且自動(dòng)識(shí)別、載入依賴,我們有兩種選擇,一、給它們?nèi)┥弦粋€(gè)叫 define 的函數(shù);二、使用 Require.js 提供的配置選項(xiàng) shim,曲線救國。
比如我手上一個(gè)項(xiàng)目,因?yàn)槟撤N原因,還在用 jQuery 1.4.1 版本,而 jQuery 是從1.7版本開始才注冊(cè)為 AMD 模塊的,我要在 require.js 中使用,就需要先做 shim:
require.config({ shim: { 'jquery-1.4.1': { // <= 這個(gè)是相對(duì)于 main.js 的路徑www.45it.com exports: 'jQuery' // <= 這個(gè)值需要稍加注意,稍后會(huì)提及 }, 'libs/jquery-throttle-debounce.min': { // <= jQuery 插件 deps: ['jquery-1.4.1'] //無需 exports,因?yàn)槲覀冎皇窃谠鰪?qiáng) jQuery 功能 } }, }); require(['jquery-1.4.1', 'libs/jquery-throttle-debounce.min'], function($){ console.log($.debounce); });
寫完 shim,發(fā)現(xiàn) jquery-1.4.1、libs/jquery-throttle-debounce.min 這樣的名稱有點(diǎn)長。這里我們又有兩種選擇,一是直接打開修改 js 文件名,或者使用 require.js 提供的配置項(xiàng) paths 給模塊 ID 指定對(duì)應(yīng)的真實(shí)文件路徑:
require.config({ paths: { 'jquery': 'jquery-1.4.1', // <= 模塊 jquery 指向 js/jquery-1.4.1.js 文件 'debounce': 'libs/jquery-throttle-debounce.min' }, shim: { 'jquery': { exports: '$' }, 'debounce': { deps: ['jquery'] } } }); require(['jquery', 'debounce'], function($){ console.log($.debounce); });
這樣,引用起來就方便多了。
另外,需要注意 shim 中的 exports 項(xiàng),它的概念更接近 imports,即把全局變量導(dǎo)入。我們?nèi)绻?exports 值改成非全局變量名,就會(huì)導(dǎo)致傳入回調(diào)的對(duì)象變成 undefined,舉個(gè)例子:
require.config({ paths: { 'jquery': 'jquery-1.4.1', }, shim: { 'jquery': { exports: 'hellojQuery' // 這里我把 exports 值設(shè)置為 jQuery/$ 以外的值 } } }); require(['jquery'], function($){ console.log($);// 這里,會(huì)顯示 undefined });
其他模塊在做 shim 時(shí)同理,比如 underscore 需要 exports 成 _。
Require.js 的好處
說了這么多,Require.js 到底有什么好處?
并行加載
我們知道,<script></script> 標(biāo)簽會(huì)阻塞頁面,加載 a.js 時(shí),后面的所有文件都得等它加載完成并執(zhí)行結(jié)束后才能開始加載、執(zhí)行。而 require.js 的模塊可以并行下載,沒有依賴關(guān)系的模塊還可以并行執(zhí)行,大大加快頁面訪問速度。
不愁依賴
在我們定義模塊的時(shí)候,我們就已經(jīng)決定好模塊的依賴 – c 依賴 b,b 又依賴 a。當(dāng)我想用 c 模塊的功能時(shí),我只要在 require函數(shù)的依賴?yán)镏付?c:
require(['c'], function(c) {...});
至于 c 依賴的模塊,c 依賴的模塊的依賴模塊… 等等,require.js 會(huì)幫我們打理。
而傳統(tǒng)的 script 辦法,我們必須明確指定所有依賴順序:
<script src="js/a.js"></script> <script src="js/b.js"></script> <script src="js/c.js"></script>
換句話說,傳統(tǒng)的 script 方法里,我們極可能要靠記憶或者檢查模塊內(nèi)容這種方式來確定依賴 – 效率太低,還費(fèi)腦。
減少全局沖突
通過 define 的方式,我們大量減少了全局變量,這樣代碼沖突的概率就極小極小 – JavaScript 界有句話說,全局變量是魔鬼,想想,我們能減少魔鬼的數(shù)量,我想是件好事。
關(guān)于全局變量
有一點(diǎn)需要說明的是,require.js 環(huán)境中并不是只有 define 和 require 幾個(gè)全局變量。許多庫都會(huì)向全局環(huán)境中暴露變量,以 jQuery 為例,1.7版本后,它雖然注冊(cè)自己為 AMD 模塊,但同時(shí)也向全局環(huán)境中暴露了 jQuery 與 $。所以以下代碼中,雖然我們沒有向回調(diào)函數(shù)傳入一份引用,jQuery/$ 同樣是存在的:
require(['jquery'], function(){ console.log(jQuery); console.log($); });
以上這篇JavaScript中Require調(diào)用js的實(shí)例分享就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
javascript運(yùn)算符——邏輯運(yùn)算符全面解析
下面小編就為大家?guī)硪黄猨avascript運(yùn)算符——邏輯運(yùn)算符詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06JavaScript高級(jí)程序設(shè)計(jì) DOM學(xué)習(xí)筆記
DOM是針對(duì)XML和HTML文檔的一個(gè)API:即規(guī)定了實(shí)現(xiàn)文本節(jié)點(diǎn)操控的屬性、方法,具體實(shí)現(xiàn)由各自瀏覽器實(shí)現(xiàn)。2011-09-09JavaScript通過極大極小值算法實(shí)現(xiàn)AI井字棋游戲
極小極大值搜索算法是一種零和算法,是用來最小化對(duì)手的利益,最大化自己的利益的算法。極小極大之搜索算法常用于棋類游戲等雙方較量的游戲和程序,算是一種電腦AI算法。本文將介紹通過這個(gè)算法實(shí)現(xiàn)的一個(gè)井字棋游戲,需要的可以參考一下2021-12-12淺析BootStrap中Modal(模態(tài)框)使用心得
Bootstrap Modals(模態(tài)框)是使用定制的 Jquery 插件創(chuàng)建的。本文給大家分享BootStrap中Modal(模態(tài)框)使用心得,一起看看吧2016-12-12javascript 刪除數(shù)組元素和清空數(shù)組的簡單方法
這篇文章主要介紹了javascript 刪除數(shù)組元素和清空數(shù)組的簡單方法的相關(guān)資料,需要的朋友可以參考下2017-02-02javascript instanceof 內(nèi)部機(jī)制探析
在 JavaScript 中,可以用 instanceof 來判斷一個(gè)對(duì)象是不是某個(gè)類或其子類的實(shí)例。2010-10-10javascript+css實(shí)現(xiàn)俄羅斯方塊小游戲
這篇文章主要為大家詳細(xì)介紹了javascript+css實(shí)現(xiàn)俄羅斯方塊小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06