首頁  >  文章  >  web前端  >  JavaScript中Require呼叫js實例講解

JavaScript中Require呼叫js實例講解

小云云
小云云原創
2018-01-20 13:31:221582瀏覽

本文主要為大家帶來一個JavaScript中Require呼叫js的實例分享。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。

在我最初開始寫JavaScript 函數時,通常是這樣的:


#
function fun1() {
 // some code here
}
function fun2() {
 // some other code here
}
...

函數全寫在全域環境中,專案很小時,通常不會有衝突問題。

但程式碼多了後,漸漸就發現,函數名稱(英文詞彙)有點不夠用了。於是引入命名空間的概念,開始模組化程式碼。

命名空間下的函數

在命名空間下,我的程式碼這樣寫:


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,
 ...
 };
}());
...

本著要物件導向的原則,執行函數通常我要這麼寫的:


com.zfanw.module1.func1.apply({},['arg1',arg2]);
...

當然,為了少打些字符,我還會在閉包中導入1公用API 介面:www.jb51.net


(function($, mod1) {
 // some code here
 mod1.func1.apply({},['arg1',arg2]);
}(jQuery, com.zfanw.module1));
...

至此,程式碼衝突的可能性已經很小,但程式碼依賴的問題,多腳本文件管理、阻塞的問題,漸漸浮出水面– 命名空間的辦法開始捉急。

於是 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 suncding to refer to gloem objects, s​​養 sdefects cem.

簡單地說,有兩點,一、模組作用域自成一體,不污染全局空間;二、模組指明依賴關係,並且依賴是透過參數傳遞的形式導入的,無需透過全域對象引用– 依賴同樣不污染全域空間。

定義模組

與上面的老長的命名空間方式不同,require.js 用全域方法define 來定義模組,形式如下:


define(id?, dependencies?, factory); // ? 表示可选项

我且把模組分兩種。

無依賴的模組

假如一個模組並不依賴其他模組,那麼定義起來是很簡單的,例如模組hello 放在hello.js 檔案中:


define(function() {
 // some code here
 return {
 // some public api
 };
});

有依賴的模組

有依賴的模組要稍稍複雜點,define 時,我們需要羅列出模組的依賴:


define(['jquery'], function($) { // 比如这个模块,代码的执行依赖 jQuery,require.js 会先加载 jquery 模块代码,并加以执行,然后将依赖模块 以 $ 的参数形式传入回调函数中,回调函数将执行结果注册为模块
 // maybe some code here
 return {
 // some public api
 };
});

這裡,依賴中的'jquery' 是模組相對於baseUrl 的路徑,等效於模組ID。

現在,再回過頭,看看上面寫過的閉包中導入公共API 的程式碼,跟define 函數做個比較:


(function($, mod1) {
 // some code here
 mod1.func1.apply({},['arg1',arg2]);
}(jQuery, com.zfanw.module1));

這段程式碼裡,我同樣把jQuery 導入了,在閉包裡,我同樣是透過$ 這個外部傳入的參數來存取jQuery。可以說,它「定義依賴」的方式跟 define 方法很相似,不同的是,define 導入的 jquery 不是全域變量,所以不會污染全域環境。

關於模組名稱

define 函數有三個參數,第一個id 即模組名稱,這個名稱的格式是相對於baseUrl 的路徑除去檔案格式,例如baseUrl 為js 目錄,一個模組放在js/libs/hi.js 裡,如果名稱是這樣定義的:


define('libs/hi', ['jquery'], function($){......});

這樣的定義形式的好處是,模組不可能衝突,因為同一目錄下不允許同名檔案。但也因此require.js 建議我們不要設定模組名稱,因為設定了'libs/hi' 的模組名稱後,模組就必須放在js/libs 目錄下的hi.js 檔案中,要移動位置的話,模組名稱要跟著改變。至於後期利用 r.js 最佳化時產生了模組名稱,那已經是另外一回事。

使用模組

在定義好「有依賴」、「沒依賴」的各種模組後,我們該怎麼用它? Require.js 提供了一個函數,require(與 requirejs 等效)。

require 函數載入依賴並執行回調,與define 不同的是,它不會把回調結果4註冊成模組:


require(['jquery'], function($) { // 这个函数加载 jquery 依赖,然后执行回调代码
 console.log($);
});

舉一個簡單的例子。我有一個資料夾,檔案結構如下:


index.html
 js/
  main.js
  require.js
  jquery.js

這裡jquery.js 已經註冊為AMD 模組,則HTML 檔案裡這樣引用require.js:


<script src="js/require.js" data-main="js/main"></script>

require.js 會檢查data-main 屬性值,這裡是js/main,根據設定,它會載入js 目錄下的main.js 檔案。

main.js 檔案裡,我只做一件事,用 jQuery 方法取得目前視窗的寬度:


require([&#39;jquery&#39;], function($) {
 var w = $(window).width();
 console.log(w);
});

執行程式碼就這麼簡單。

非 AMD 規範的模組

但事情远没有我们想像中那么美好,AMD 只是一种社区规范,并非标准,而且在它出现以前,已经有各种各样的流行库存在,更不用说我们自己早期写的代码,所以我们一定会碰上一堆非 AMD 规范的模块。为了让 require.js 能够加载它们,并且自动识别、载入依赖,我们有两种选择,一、给它们全穿上一个叫 define 的函数;二、使用 Require.js 提供的配置选项 shim,曲线救国。

比如我手上一个项目,因为某种原因,还在用 jQuery 1.4.1 版本,而 jQuery 是从1.7版本开始才注册为 AMD 模块的,我要在 require.js 中使用,就需要先做 shim:


require.config({
 shim: {
  &#39;jquery-1.4.1&#39;: { // <= 这个是相对于 main.js 的路径www.45it.com
   exports: &#39;jQuery&#39; // <= 这个值需要稍加注意,稍后会提及
  },
  &#39;libs/jquery-throttle-debounce.min&#39;: { // <= jQuery 插件
   deps: [&#39;jquery-1.4.1&#39;] //无需 exports,因为我们只是在增强 jQuery 功能
  }
 },
});
require([&#39;jquery-1.4.1&#39;, &#39;libs/jquery-throttle-debounce.min&#39;], function($){
 console.log($.debounce);
});

写完 shim,发现 jquery-1.4.1、libs/jquery-throttle-debounce.min 这样的名称有点长。这里我们又有两种选择,一是直接打开修改 js 文件名,或者使用 require.js 提供的配置项 paths 给模块 ID 指定对应的真实文件路径:


require.config({
 paths: {
  &#39;jquery&#39;: &#39;jquery-1.4.1&#39;, // <= 模块 jquery 指向 js/jquery-1.4.1.js 文件
  &#39;debounce&#39;: &#39;libs/jquery-throttle-debounce.min&#39;
 },
 shim: {
  &#39;jquery&#39;: {
   exports: &#39;$&#39;
  },
  &#39;debounce&#39;: {
   deps: [&#39;jquery&#39;]
  }
 }
});
require([&#39;jquery&#39;, &#39;debounce&#39;], function($){
 console.log($.debounce);
});

这样,引用起来就方便多了。

另外,需要注意 shim 中的 exports 项,它的概念更接近 imports,即把全局变量导入。我们如果把 exports 值改成非全局变量名,就会导致传入回调的对象变成 undefined,举个例子:


require.config({
 paths: {
  &#39;jquery&#39;: &#39;jquery-1.4.1&#39;,
 },
 shim: {
  &#39;jquery&#39;: {
   exports: &#39;hellojQuery&#39; // 这里我把 exports 值设置为 jQuery/$ 以外的值
  }
 }
});
require([&#39;jquery&#39;], function($){
 console.log($);// 这里,会显示 undefined
});

其他模块在做 shim 时同理,比如 underscore 需要 exports 成 _。

Require.js 的好处

说了这么多,Require.js 到底有什么好处?

并行加载

我们知道,3f1c4e4b6b16bbbd69b2ee476dc4f83a2cacc6d41bbb37262a98f745aa00fbf0 标签会阻塞页面,加载 a.js 时,后面的所有文件都得等它加载完成并执行结束后才能开始加载、执行。而 require.js 的模块可以并行下载,没有依赖关系的模块还可以并行执行,大大加快页面访问速度。

不愁依赖

在我们定义模块的时候,我们就已经决定好模块的依赖 – c 依赖 b,b 又依赖 a。当我想用 c 模块的功能时,我只要在 require函数的依赖里指定 c:

require(['c'], function(c) {...});

至于 c 依赖的模块,c 依赖的模块的依赖模块… 等等,require.js 会帮我们打理。

而传统的 script 办法,我们必须明确指定所有依赖顺序:


<script src="js/a.js"></script>
 <script src="js/b.js"></script>
 <script src="js/c.js"></script>

换句话说,传统的 script 方法里,我们极可能要靠记忆或者检查模块内容这种方式来确定依赖 – 效率太低,还费脑。

减少全局冲突

通过 define 的方式,我们大量减少了全局变量,这样代码冲突的概率就极小极小 – JavaScript 界有句话说,全局变量是魔鬼,想想,我们能减少魔鬼的数量,我想是件好事。

关于全局变量

有一点需要说明的是,require.js 环境中并不是只有 define 和 require 几个全局变量。许多库都会向全局环境中暴露变量,以 jQuery 为例,1.7版本后,它虽然注册自己为 AMD 模块,但同时也向全局环境中暴露了 jQuery 与 $。所以以下代码中,虽然我们没有向回调函数传入一份引用,jQuery/$ 同样是存在的:


require([&#39;jquery&#39;], function(){
 console.log(jQuery);
 console.log($);
});

相关推荐:

a标签不能调用js方法的问题

iframe子父页面调用js函数示例

php如何调用js方法

以上是JavaScript中Require呼叫js實例講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn