JavaScriptのモジュール開発について詳しく解説

黄舟
リリース: 2017-02-21 11:57:56
オリジナル
1461 人が閲覧しました



モジュール開発とは何ですか?

フロントエンド開発では、最初は、スクリプト タグに数十行または数百行のコードを埋め込むことで、いくつかの基本的なインタラクティブ効果を実現できましたが、その後、js が注目を集め、jQuery、Ajax、Node.Js など、広く使用されるようになりました。 MVC や MVVM の助けを借りて、フロントエンド開発にも注目が集まっており、フロントエンド プロジェクトはますます複雑になってきていますが、JavaScript はコードを整理するのに明確な助けを提供しません。モジュールはおろか、クラスの概念さえありません。では、モジュールとは何でしょうか?

モジュールは、特定の機能を実装するファイルです。モジュールを使用すると、必要な機能に必要なモジュールをより便利に使用できます。モジュール開発は特定の規範に従う必要があります。そうしないと、すべてが台無しになってしまいます。

AMD 仕様に従って、define を使用してモジュールを定義し、require を使用してモジュールを呼び出すことができます。

現在、主によく使われている js モジュール仕様は CommonJS と AMD の 2 つです。

AMD仕様

AMDとはAsynchronous Module Definitionのことで、中国語名は「非同期モジュール定義」を意味します。ブラウザ側でのモジュール開発の仕様であり、サーバー側ではCommonJS

モジュールが非同期でロードされ、モジュールのロードは後続のステートメントの実行に影響を与えません。特定のモジュールに依存するすべてのステートメントはコールバック関数に配置されます。

AMD は、RequireJS のプロモーション プロセス中のモジュール定義の標準化された出力です。

define() 関数

AMD 仕様では、グローバル変数である関数 define が 1 つだけ定義されています。関数の説明は次のとおりです:

define(id?, dependencies?, factory);
ログイン後にコピー

パラメータの説明:

id:指定义中模块的名字,可选;如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。

依赖dependencies:是一个当前模块依赖的,已被模块定义的模块标识的数组字面量。
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。

工厂方法factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
ログイン後にコピー

モジュール名の形式

モジュール名は、定義内でモジュールを一意に識別するために使用されます。これらは依存関係配列でも使用されます:

模块名是用正斜杠分割的有意义单词的字符串
单词须为驼峰形式,或者".",".."
模块名不允许文件扩展名的形式,如“.js”
模块名可以为 "相对的" 或 "顶级的"。如果首字符为“.”或“..”则为相对的模块名
顶级的模块名从根命名空间的概念模块解析
相对的模块名从 "require" 书写和调用的模块解析
ログイン後にコピー

requireとexportsを使用します

require、exports、および「beta」という名前のモジュールを使用して、「alpha」という名前のモジュールを作成します:

 define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
       exports.verb = function() {
           return beta.verb();
           //Or:
           return require("beta").verb();
       }
   });
ログイン後にコピー

require APIの概要: //m.sbmmt.com/

AMD仕様中国語版: //m.sbmmt.com/(%E4%B8%AD%E6%96%87%E7%89%88)

現在、AMD を実装するライブラリには、RequireJS、curl、Dojo、Nodules、等

CommonJS仕様

CommonJSはサーバーサイドモジュールの仕様であり、Node.jsはこの仕様を採用しています。 Node.JS は、js モジュール性の概念を初めて採用しました。

CommonJS 仕様によれば、単一のファイルがモジュールです。各モジュールには個別のスコープがあります。つまり、モジュール内で定義された変数は、グローバル オブジェクトの属性として定義されない限り、他のモジュールから読み取ることができません。

モジュール変数をエクスポートする最良の方法は、 module.exports オブジェクトを使用することです。

var i = 1;
var max = 30;

module.exports = function () {
  for (i -= 1; i++ < max; ) {
    console.log(i);
  }
  max *= 1.1;
};
ログイン後にコピー

上記のコードは、モジュールの外部通信と内部通信の間のブリッジである module.exports オブジェクトを通じて関数を定義します。

require メソッドを使用してモジュールをロードします。このメソッドはファイルを読み取って実行し、最後にファイル内の module.exports オブジェクトを返します。

CommonJS 仕様: //m.sbmmt.com/

RequireJS および SeaJS

RequireJS は、AMD 仕様の創設者でもある James Burke によって作成されました。

define メソッドはモジュールを定義するために使用されます。RequireJS では、各モジュールを別のファイルに配置する必要があります。

RequireJS と Sea.js は両方ともモジュール ローダーであり、モジュール開発の概念を提唱しており、その中心的な価値は JavaScript のモジュール開発をシンプルかつ自然にすることです。

SeaJS と RequireJS の最大の違い:

SeaJS のモジュールに対する態度は遅延実行ですが、RequireJS のモジュールに対する態度は事前実行です

理解できませんか?写真とテキスト付きのこの記事をご覧ください: //m.sbmmt.com/

RequireJS API: //m.sbmmt.com/

RequireJS の使用方法: //m.sbmmt.com /

requireJS を使用する理由

想像してみてください。Web ページに大量の JS ファイルがある場合、ブラウザはページをダウンロードするときに最初に JS ファイルをロードするため、さらに多くのファイルがある場合、Web ページのレンダリングが停止します。ブラウザが応答を失う可能性があります。次に、js ファイルの依存関係を確保する必要があります。依存関係が複雑になると、コードの作成と保守が困難になります。

RequireJS は、次の 2 つの問題を解決するために生まれました:

(1)实现js文件的异步加载,避免网页失去响应;
(2)管理模块之间的依赖性,便于代码的编写和维护。
ログイン後にコピー

RequireJS ファイルのダウンロード: //m.sbmmt.com/

AMD および CMD

CMD (共通モジュール定義) 共通モジュール定義。この仕様は、モジュールの基本的な記述形式と基本的な対話ルールを明確にします。この基準は国内で開発されました。 AMD はフロントエンドに依存しており、CMD はオンデマンドでロードされます。

CMD 仕様では、モジュールはファイルです。コードの記述形式は以下の通りです:

define(factory);
ログイン後にコピー

ファクトリーが関数の場合、モジュールの構築メソッドを意味します。この構築方法を実行することで、モジュールが提供するインターフェースを取得することができます。ファクトリ メソッドが実行されると、デフォルトで、require、exports、module の 3 つのパラメータが渡されます。

define(function(require, exports, module) {

  // 模块代码

});
ログイン後にコピー

require は他のモジュールをインポートできるパラメータであり、export はモジュール内の一部のプロパティとメソッドをエクスポートできます。

CMD仕様アドレス: //m.sbmmt.com/

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
ログイン後にコピー

依存モジュールについては、AMDが先行して実行され、CMDは遅延して実行されます。

AMD:提前执行(异步加载:依赖先执行)+延迟执行
CMD:延迟执行(运行到需加载,根据顺序执行)
ログイン後にコピー

CMD は近くの依存関係を主張し、AMD は手前の依存関係を主張します。次のコードを見てください:

// CMD
define(function(require, exports, module) {
var a = require(&#39;./a&#39;)
a.doSomething()
// 此处略去 100 行
var b = require(&#39;./b&#39;) // 依赖可以就近书写
b.doSomething()
// ... 
})

// AMD 默认推荐的是
define([&#39;./a&#39;, &#39;./b&#39;], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()
...
})
ログイン後にコピー

另外一个区别是:

AMD:API根据使用范围有区别,但使用同一个api接口
CMD:每个API的职责单一
ログイン後にコピー

AMD的优点是:异步并行加载,在AMD的规范下,同时异步加载是不会产生错误的。
CMD的机制则不同,这种加载方式会产生错误,如果能规范化模块内容形式,也可以

jquery1.7以上版本会自动模块化,支持AMD模式:主要是使用define函数,sea.js虽然是CommonJS规范,但却使用了define来定义模块
所以jQuery已经自动模块化了

seajs.config({

&#39;base&#39;:&#39;/&#39;,

&#39;alias&#39;:{

    &#39;jquery&#39;:&#39;jquery.js&#39;//定义jQuery文件

}
});
ログイン後にコピー

define函数和AMD的define类似:

define(function(require, exports, module{

     //先要载入jQuery的模块

     var $ = require(&#39;jquery&#39;);

     //然后将jQuery对象传给插件模块

     require(&#39;./cookie&#39;)($);

     //开始使用 $.cookie方法

});
ログイン後にコピー

sea.js如何使用?

  • 引入sea.js的库

  • 如何变成模块?

    • define

  • 3.如何调用模块?

         -exports
         -sea.js.use
    ログイン後にコピー
  • 4.如何依赖模块?

         -require
    
    <script type="text/javascript">
           define(function (require,exports,module) {
               //exports : 对外的接口
               //requires : 依赖的接口
               require(&#39;./test.js&#39;);//如果地址是一个模块的话,那么require的返回值就是模块中的exports
           })
    ログイン後にコピー

sea.js 开发实例

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>鼠标拖拽的模块化开发实践</title>
<style type="text/css">
#p1{ width:200px; height:200px; background:black; position:absolute; display:none;}
#p2{ width:30px; height:30px; background:yellow; position:absolute; bottom:0; right:0;}
#p3{ width:100px; height:100px; background:blue; position:absolute; right:0; top:0;}
</style>
<script type="text/javascript" src="./sea.js"></script>
<script type="text/javascript">
    
//A同事 :
seajs.use(&#39;./main.js&#39;);
    
</script>
</head>

<body>
<input type="button" value="确定" id="input1" />
<p id="p1">
    <p id="p2"></p>
</p>
<p id="p3"></p>
</body>
</html>
ログイン後にコピー

A同事

//A同事写的main.js:

define(function (require,exports,module) {
    var oInput = document.getElementById(&#39;input1&#39;);
    var op1 = document.getElementById(&#39;p1&#39;);
    var op2 = document.getElementById(&#39;p2&#39;);
    var op3 = document.getElementById(&#39;p3&#39;);

    require(&#39;./drag.js&#39;).drag(op3);
    oInput.onclick = function () {
        op1.style.display = &#39;block&#39;;
        require(&#39;./scale.js&#39;).scale(op1,op2);

        require.async(&#39;./scale.js&#39;, function (ex) {
            ex.scale(op1,op2);
        })
    }
});
ログイン後にコピー

B同事

//B同事写的drag.js:

define(function(require,exports,module){
    
    function drag(obj){
        var disX = 0;
        var disY = 0;
        obj.onmousedown = function(ev){
            var ev = ev || window.event;
            disX = ev.clientX - obj.offsetLeft;
            disY = ev.clientY - obj.offsetTop;
            
            document.onmousemove = function(ev){
                var ev = ev || window.event;


                 var L = require(&#39;./range.js&#39;).range(ev.clientX - disX , document.documentElement.clientWidth - obj.offsetWidth , 0 );
                 var T = require(&#39;./range.js&#39;).range(ev.clientY - disY , document.documentElement.clientHeight - obj.offsetHeight , 0 );

                
                obj.style.left = L + &#39;px&#39;;
                obj.style.top = T + &#39;px&#39;;
            };
            document.onmouseup = function(){
                document.onmousemove = null;
                document.onmouseup = null;
            };
            return false;
        };
    }
    
    exports.drag = drag;//对外提供接口
    
});
ログイン後にコピー

C同事

//C同事写的scale.js:

define(function(require,exports,module){
    
    
    function scale(obj1,obj2){
        var disX = 0;
        var disY = 0;
        var disW = 0;
        var disH = 0;
        
        obj2.onmousedown = function(ev){
            var ev = ev || window.event;
            disX = ev.clientX;
            disY = ev.clientY;
            disW = obj1.offsetWidth;
            disH = obj1.offsetHeight;
            
            document.onmousemove = function(ev){
                var ev = ev || window.event;
                
                var W = require(&#39;./range.js&#39;).range(ev.clientX - disX + disW , 500 , 100);
                var H = require(&#39;./range.js&#39;).range(ev.clientY - disY + disH , 500 , 100);
                
                obj1.style.width = W + &#39;px&#39;;
                obj1.style.height = H + &#39;px&#39;;
            };
            document.onmouseup = function(){
                document.onmousemove = null;
                document.onmouseup = null;
            };
            return false;
        };
        
    }
    
    exports.scale = scale;
    
});
ログイン後にコピー

D同事

// D同事的range.js--限定拖拽范围

    define(function(require,exports,module){
        
        function range(iNum,iMax,iMin){
            
            if( iNum > iMax ){
                return iMax;
            }
            else if( iNum < iMin ){
                return iMin;
            }
            else{
                return iNum;
            }
            
        }
        
        exports.range = range;
        
    });
ログイン後にコピー

requirejs开发实例

require.config是用来定义别名的,在paths属性下配置别名。然后通过requirejs(参数一,参数二);参数一是数组,传入我们需要引用的模块名,第二个参数是个回调函数,回调函数传入一个变量,代替刚才所引入的模块。

main.js文件

//别名配置
requirejs.config({
    paths: {
        jquery: &#39;jquery.min&#39; //可以省略.js
    }
});
//引入模块,用变量$表示jquery模块
requirejs([&#39;jquery&#39;], function ($) {
    $(&#39;body&#39;).css(&#39;background-color&#39;,&#39;red&#39;);
});
ログイン後にコピー

引入模块也可以只写require()。requirejs通过define()定义模块,定义的参数上同。在此模块内的方法和变量外部是无法访问的,只有通过return返回才行.

define 模块

define([&#39;jquery&#39;], function ($) {//引入jQuery模块
    return {
        add: function(x,y){
            return x + y;
        }
    };
});
ログイン後にコピー

将该模块命名为math.js保存。

main.js引入模块方法

require([&#39;jquery&#39;,&#39;math&#39;], function ($,math) {
    console.log(math.add(10,100));//110
});
ログイン後にコピー

没有依赖

如果定义的模块不依赖其他模块,则可以:

define(function () {

    return {
        name: "trigkit4",
        age: "21"
    }
});
ログイン後にコピー

AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的。

以上就是详解JavaScript模块化开发的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!


ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート