今回は Require to call js の使い方について詳しく説明します。 Require to call 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]); ...
もちろん、文字入力を節約するために、クロージャにパブリック 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 のモジュールの概念を理解します:
モジュールは、次の点で従来のスクリプト ファイルとは異なります。 グローバル名前空間の汚染を回避する、適切な範囲のオブジェクトを定義します。 依存関係を明示的にリストし、それらのハンドルを取得できます。 依存関係をグローバル オブジェクトを参照する必要はありませんが、その代わりに 依存関係を定義する関数の引数として受け取ります。 モジュール。
簡単に言うと、2 つの点があります。1 つは、モジュールのスコープが自己完結型であり、グローバル空間を汚染しないことです。2 つ目は、モジュールが依存関係を指定し、グローバル オブジェクト (依存関係) を参照することなく、パラメーターの受け渡しによって依存関係がインポートされることです。地球空間を汚染することもありません。
モジュールを定義する
上記の長い名前空間メソッドとは異なり、require.js はグローバル メソッド define を使用して次の形式でモジュールを定義します:
define(id?, dependencies?, factory); // ? 表示可选项
モジュールを 2 種類に分けて説明します。
依存関係のないモジュール
モジュールが他のモジュールに依存しない場合、定義は非常に簡単です。たとえば、モジュール hello は hello.js ファイルに配置されます:
define(function() { // some code here return { // some public api }; });
。 依存関係のあるモジュール
依存関係のあるモジュールを定義する場合は、モジュールの依存関係をリストする必要があります:
define(['jquery'], function($) { // 比如这个模块,代码的执行依赖 jQuery,require.js 会先加载 jquery 模块代码,并加以执行,然后将依赖模块 以 $ 的参数形式传入回调函数中,回调函数将执行结果注册为模块 // maybe some code here return { // some public api }; });
ここで、依存関係内の「jquery」は、baseUrl を基準としたモジュールの相対パスであり、モジュール ID に相当します。
ここで、上で書いたクロージャ内のパブリック API をインポートするコードに戻って、定義関数と比較してください:
(function($, mod1) { // some code here mod1.func1.apply({},['arg1',arg2]); }(jQuery, com.zfanw.module1));
このコードでは、クロージャ内で外部パラメータ $ を介して jQuery もインポートしました。 「依存関係を定義する」方法は、define メソッドに非常に似ていると言えます。違いは、define によってインポートされた jquery がグローバル変数ではないため、グローバル環境を汚染しないことです。
モジュール名について
この定義関数には 3 つのパラメーターがあります。最初の ID はモジュール名です。この名前の形式は、baseUrl からファイル形式を引いた相対パスです。たとえば、baseUrl は 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(['jquery'], 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: { 'jquery-1.4.1': { // <= 这个是相对于 main.js 的路径www.45it.com exports: 'jQuery' // <= 这个值需要稍加注意,稍后会提及 }, 'libs/jquery-throttle-debounce.min': { // <= jQuery 插件 deps: ['jquery-1.4.1'] //无需 exports,因为我们只是在增强 jQuery 功能 } }, }); require(['jquery-1.4.1', 'libs/jquery-throttle-debounce.min'], function($){ console.log($.debounce); });
写完 shim,发现 jquery-1.4.1、libs/jquery-throttle-debounce.min 这样的名称有点长。这里我们又有两种选择,一是直接打开修改 js 文件名,或者使用 require.js 提供的配置项 paths 给模块 ID 指定对应的真实文件路径:
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 项,它的概念更接近 imports,即把全局变量导入。我们如果把 exports 值改成非全局变量名,就会导致传入回调的对象变成 undefined,举个例子:
require.config({ paths: { 'jquery': 'jquery-1.4.1', }, shim: { 'jquery': { exports: 'hellojQuery' // 这里我把 exports 值设置为 jQuery/$ 以外的值 } } }); require(['jquery'], function($){ console.log($);// 这里,会显示 undefined });
其他模块在做 shim 时同理,比如 underscore 需要 exports 成 _。
Require.js 的好处
说了这么多,Require.js 到底有什么好处?
并行加载
我们知道,<script></script> 标签会阻塞页面,加载 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(['jquery'], function(){ console.log(jQuery); console.log($); });
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
js+css により、Web ページを読み込む際のユーザー エクスペリエンスが向上します
以上がRequire to call jsの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。