CMD規范學習筆記——基於SEAJS實現


CMD(Common Module Definition):該規范明確了模塊的書寫格式和基本交互規則。通常一個模塊就是一個JS文件。

通過define關鍵字來定義模塊,最基本的格式為:

define(factory);//這里的define是一個全局函數,factory可以是函數或者合法的值。

一、factory為對象:

define({'foo':'foo'});//factory為對象,表示該模塊的接口為對象。

例子:

html

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>CMD規范的Define函數</title>

<script type="text/javascript" src="../../sea-modules/seajs/seajs/2.2.0/sea.js"></script>

<script type="text/javascript">

   seajs.use("../../static/cmd/main");//使用模塊

</script>

</head>

<body>

</body>

</html>

定義模塊1:cmdDefine.js

/**

 * define(factory)

 * 模塊通過define關鍵字定義,它是一個全局的方法,factory可以是方法或者是對象和字符串等合法的值

 */

//定義一個模塊,該模塊的對象接口為{'foo':"foo"}

define({'foo':"foo"});

定義模塊2:main.js

/**

 * 當factory為函數時,可以接受3個參數,function(require,exports,module)

 */

define(function(require) {

   //通過riquire引用模塊

   var cmdDefine=require('./cmdDefine');

   alert(cmdDefine.foo);//輸出對象foo

});

結果:

 

 

二、factory為字符串

define("This is Test!");

結果:

 

 

三、factory為數字

define(100);

結果:

 

 

 

四、當factory函數

cmdDefine.js

/**

 * define(factory)

 * 模塊通過define關鍵字定義,它是一個全局的方法,factory可以是方法或者是對象和字符串等合法的值

 */

//定義一個模塊,該模塊的對象接口為{'foo':"foo"}

//define({'foo':"foo"});//對象

//define("This is Test!");//字符串

//define(100);//數字

//factory為函數

define(function(require,exports,module){

   //構造函數

   function CmdDefine(){

      alert("This is CmdDefine Constructor!");

   }

   //每個函數都有一個prototype原型對象,可以在原型對象上添加屬性和方法,實例化對象的_proto_指向原型對象

   CmdDefine.prototype.say=function(){

      alert("This is CmdDefine say function!");

   }

   module.exports=CmdDefine;//對外發布接口

});

main.js

/**

 * 當factory為函數時,可以接受3個參數,function(require,exports,module)

 */

define(function(require) {

   //通過riquire引用模塊

   var CmdDefine=require('./cmdDefine');

   //alert(cmdDefine.foo);//輸出對象foo

   //alert(cmdDefine);//輸出字符串This is Test!

   var tmp = new CmdDefine();//創建CmdDefine實例

   tmp.say();//調用say方法

});

結果:

 

 

五、define  也可以接受兩個以上參數。字符串  id  表示模塊標識,數組deps是模塊依賴。帶id和deps參數的define用法不屬於 CMD 規范,而屬於 Modules/Transport 規范。比如:

/**

 * define(factory)

 * 模塊通過define關鍵字定義,它是一個全局的方法,factory可以是方法或者是對象和字符串等合法的值

 */

//定義一個模塊,該模塊的對象接口為{'foo':"foo"}

//define({'foo':"foo"});//對象

//define("This is Test!");//字符串

//define(100);//數字

//factory為函數

//define('cmdDefine',['jquery'],function(require,exports,module)

//define接收3個參數,第一個為模塊標識,第二個為依賴模塊數組

define('cmdDefine',['jquery'],function(require,exports,module){

   //構造函數

   function CmdDefine(){

      alert("This is CmdDefine Constructor!");

   }

   //每個函數都有一個prototype原型對象,可以在原型對象上添加屬性和方法,實例化對象的_proto_指向原型對象

   CmdDefine.prototype.say=function(){

      alert("This is CmdDefine say function!");

   }

   module.exports=CmdDefine;//對外發布接口

});

在seajs中id和deps參數可以省略。省略時,可以通過構建工具自動生成。

六、判斷當前頁面是否有CMD模塊加載器

define.cmd,一個空的對象可以用來判斷當前頁面是否存在CMD模塊加載器。

if(tepyof  define === "function" && define.cmd){

// 有 Sea.js 等 CMD 模塊加載器存在

}

七、require:是factory為函數時的第一個參數,也是一個函數,接受一個參數(模塊標識ID),用於獲取其他模塊提供的接口。

/**

 * 當factory為函數時,可以接受3個參數,function(require,exports,module)

 */

define(function(require) {

   //通過riquire獲取cmdDefine對外提供的接口

   var CmdDefine=require('./cmdDefine');

   //alert(cmdDefine.foo);//輸出對象foo

   //alert(cmdDefine);//輸出字符串This is Test!

   var tmp = new CmdDefine();//創建CmdDefine實例

   tmp.say();//調用say方法

});

八、require.async:是一個方法,接受兩個參數(id,callback) ,用於在模塊內異步加載模塊,並在模塊加載完成之后調用回調函數,callback為可選。require是同步往下執行, require.async則是異步回調執行。 require.async 一般用來加載可延遲異步加載的模塊。

實際測試中tmp為null,存在問題。

/**

 * 當factory為函數時,可以接受3個參數,function(require,exports,module)

 */

define(function(require) {

   //通過riquire引用模塊

   require.async('./cmdDefine',function(tmp){

      alert("模塊加載完成");

     //tmp.say();//調用say方法

   });

});

九、require.resolve:require.resolve(id)

使用模塊系統內部的路徑解析機制來解析並返回模塊路徑。該函數不會加載模塊,只返回解析后的絕對路徑。這可以用來獲取模塊路徑,一般用在插件環境或需動態拼接模塊路徑的場景下。

/**

 * 當factory為函數時,可以接受3個參數,function(require,exports,module)

 */

define(function(require) {

   //通過riquire引用模塊

   var path=require.resolve('./cmdDefine');

   alert(path);

});

結果:

 

 

十、exports:Object,是一個對象,用於模塊對外提供接口。exports  僅僅是  module.exports  的一個引用。在factory內部exports重新賦值時,並不會改變module.exports的值。因此給  exports賦值是無效的,不能用來更改模塊接口。

第一種寫法:通過exports添加屬性或方法

define(function(require,exports,module){

   exports.foo='foo';

   exports.print=function(){

      console.log('foo');

   }

});

第二種寫法:直接通過return對外提供接口

define(function(require){

   return {

      foo:'foo',

      print:function(){

         console.log('foo');

      }

   }

});

第三種寫法:如果return語句是模塊的唯一代碼,可以省略return

define({

   foo : 'foo',

   print : function() {

      console.log('foo');

   }

});

第四種寫法:通過module.exports對外提供接口

/**

 * define(factory)

 * 模塊通過define關鍵字定義,它是一個全局的方法,factory可以是方法或者是對象和字符串等合法的值

 */

define('cmdDefine',['jquery'],function(require,exports,module){

   //構造函數

   function CmdDefine(){

      alert("This is CmdDefine Constructor!");

   }

   //每個函數都有一個prototype原型對象,可以在原型對象上添加屬性和方法,實例化對象的_proto_指向原型對象

   CmdDefine.prototype.say=function(){

      alert("This is CmdDefine say function!");

   }

   module.exports=CmdDefine;//對外發布接口

});

直接給exports賦值是錯誤的。

/**

 * 不能通過給exports變量賦值對外提供接口,

 * exports只是module.exports的引用,

 * 直接賦值無法改變module.exports的值

 *

 */

define(function(require) {

   exports = {

      foo : 'foo',

      print : function() {

         console.log('foo');

      }

   }

});

十一:module :Object,是一個對象,它儲存與當前模塊相關聯的屬性和方法。

1、module .id:String,模塊唯一標識是一個字符串。define函數的第一個參數為模塊ID。

/**

 * define(factory)

 * 模塊通過define關鍵字定義,它是一個全局的方法,factory可以是方法或者是對象和字符串等合法的值

 */

define('cmdDefine',['jquery'],function(require,exports,module){

   //構造函數

   function CmdDefine(){

      alert("This is CmdDefine Constructor!");

   }

   //每個函數都有一個prototype原型對象,可以在原型對象上添加屬性和方法,實例化對象的_proto_指向原型對象

   CmdDefine.prototype.say=function(){

      alert("This is CmdDefine say function!");

   }

   module.exports=CmdDefine;//對外發布接口

});

2、module.uri:String: 根據模塊系統的路徑解析規則得到的模塊絕對路徑。一般情況下(沒有在define中手寫id  參數時),module.id的值就是module.uri ,兩者完全相同。

define(function(require,exports,module) {

   alert(`"id:"${module.id}`);//模塊id

   alert(`"uri:"${module.uri}`);

});

結果:

 

 

 

3、module.dependencies:Array:是一個數組,表示當前模塊的依賴。

4、module.exports:Object :當前模塊對外提供的接口。

傳factory構造方法的exports參數是 module.exports 對象的一個引用。只通過 exports 參數來提供接口,有時無法滿足開發者的所有需求。比如當模塊的接口是某個類的實例時,需要通過  module.exports  來實現:

define(function(require, exports, module) {

  // exports 是 module.exports 的一個引用

  console.log(module.exports === exports); // true

  // 重新給 module.exports 賦值

  module.exports = new SomeClass();

  // exports 不再等於 module.exports

  console.log(module.exports === exports); // false

});

對 module.exports 的賦值需要同步執行,不能放在回調函數里。下面這樣是不行的:

//x.js

define(function(require, exports, module) {

  // 錯誤用法

  setTimeout(function() {

    module.exports = { a: "hello" };

  }, 0);

});

在 y.js 里有調用到上面的 x.js:

//y.js

define(function(require, exports, module) {

  var x = require('./x');

  // 無法立刻得到模塊 x 的屬性 a

  console.log(x.a); // undefined

});

 

CMD規范:https://github.com/cmdjs/specification/blob/master/draft/module.md

Common Module Definition / draft

 

 

This specification addresses how modules should be written in order to be interoperable in browser-based environment. By implication, this specification defines the minimum features that a module system must provide in order to support interoperable modules.

•Modules are singletons.

•New free variables within the module scope should not be introduced.

•Execution must be lazy.

 

Module Definition

 

A module is defined with  define  keyword, which is a function.

 

define(factory);

1.The  define  function accepts a single argument, the module factory.

2.The  factory  may be a function or other valid values.

3.If  factory  is a function, the first three parameters of the function, if specified, must be "require", "exports", and "module", in that order.

4.If  factory  is not a function, then the module's exports are set to that object.

 

Module Context

 

In a module, there are three free variables:  require ,  exports  and  module .

 

define(function(require, exports, module) {

  // The module code goes here

});

 

The  require  Function

 

1. require  is a function

i. require  accepts a module identifier.

ii. require  returns the exported API of the foreign module.

iii.If requested module cannot be returned,  require  should return null.

 

 

2. require.async  is a function

i. require.async  accepts a list of module identifiers and a optional callback function.

ii.The callback function receives module exports as function arguments, listed in the same order as the order in the first argument.

iii.If requested module cannot be returned, the callback should receive null correspondingly.

 

 

The  exports  Object

 

In a module, there is a free variable called "exports", that is an object that the module may add its API to as it executes.

 

The  module  Object

 

1. module.uri

 

The full resolved uri to the module.

 

 

2. module.dependencies

 

A list of module identifiers that required by the module.

 

 

3. module.exports

 

The exported API of the module. It is the same as  exports  object.

 

 

Module Identifier

1.A module identifier is and must be a literal string.

2.Module identifiers may not have a filename extensions like  .js .

3.Module identifiers should be dash-joined string, such as  foo-bar .

4.Module identifiers can be a relative path, like  ./foo  and  ../bar .

 

Sample Code

 

A typical sample

 

math.js

 

define(function(require, exports, module) {

  exports.add = function() {

    var sum = 0, i = 0, args = arguments, l = args.length;

    while (i < l) {

      sum += args[i++];

    }

    return sum;

  };

});

 

increment.js

 

define(function(require, exports, module) {

  var add = require('math').add;

  exports.increment = function(val) {

    return add(val, 1);

  };

});

 

program.js

 

define(function(require, exports, module) {

  var inc = require('increment').increment;

  var a = 1;

  inc(a); // 2

  module.id == "program";

});

 

Wrapped modules with non-function factory

 

object-data.js

 

define({

    foo: "bar"

});

 

array-data.js

 

define([

    'foo',

    'bar'

]);

 

string-data.js

define('foo bar');

原文:https://github.com/seajs/seajs/issues/242


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM