js手札--關於AMD的簡單分析

AMD中define常見的形式

define('alpha' ,['require', "exports", "module"], function(require, exports, module) {
  var foo = require('foo');
  module.exports = exports = function() {
    foo.doSomething();
  }
});

參數node

第一個是要定義的模塊名字(id)
第二個是要用到的模塊名,其實更專業點講是定義的這個模塊所依賴的模塊名稱
第三個回調函數,是要定義模塊內容app

分析define的回調函數

分析方法:替換部分代碼進行分析模塊化

先來把回調中的require,exports,module替換了看看。函數

1.替換require

function callback(exports, module) {
  // 假設foo是最簡單的對象,把require('foo')換成最簡答的對象看看
  var foo = {
    'doSomething': function() {}
  };

  module.exports = exports = function() {
    foo.doSomething();
  }
}

那麼其實已經不難看出,require其實就至關因而個查詢函數吧,我給他傳個對象名,它就能給我一個具體的對象。優化

var require = function(name) {
  var modules = {'foo': {'doSomething': function() {}}};
  return modules[name] || {};
}

那麼整個代碼能夠換成ui

var require = function(name) {
  var modules = {'foo': {'doSomething': function() {}}};
  return modules[name] || {};
}

function callback(exports, module) {
  var foo = require('foo');
  module.exports = exports = function() {
    foo.doSomething();
  }
}

看起來好像有點道理哦,等會兒,等會兒,這裏的modules又從哪兒冒出來的,哈哈哈,被發現了,別急慢慢來code

2. 替換exports和module.exports

在替換以前,先來了解下exports和module.exports這兩貨是幹啥的,而要了解他們先來看看模塊是啥。對象

其實模塊麼,簡單來講就是一個高級別的function,輸入,處理,輸出。至於爲啥js的模塊化爲啥這麼困難,這個問題不是三言兩語就能解釋清楚的,就不展開了(其實真實狀況是,我也不清楚,哈哈哈)內存

既然模塊要作輸出,那麼輸出什麼東西總要知道吧,而module.exports的做用就是這個,存儲模塊輸出的內容。get

也就是說,這個模塊中要給外部使用的東西全放在module.exports裏頭了。廢話真多,是的哈- -.

而要說清exports和module.exports的二三事,又不是件容易的事,簡單理解,exports和module.exports指向同一內存區域。有興趣能夠看看exports 和 module.exports 的區別

那來改造一下,把module.exports,exports也提煉出來看看

var require = function(name) {
  var modules = {'foo': {'doSomething': function() {}}};
  return modules[name] || {};
}

var module = {};
var module.exports = exports = {};

function callback() {
  var foo = require('foo');

  module.exports = exports = function() {
    foo.doSomething();
  }
}

define的推測

// 這裏的id至關於模塊名,deps就是須要依賴的模塊名稱列表
define = function(id , deps, callback) {
  callback(require, exports, module);
};

暈,那require,exports,module跑哪兒溜達去了?加上去看看

define = function(id , deps, callback) {
  
  var require = function(name) {
    var modules = {'foo': {'doSomething': function() {}}};
    return modules[name] || {};
  }

  var module = {};
  var module.exports = exports = {};

  callback(require, exports, module);
};

看上去挺有道理的麼,那麼modules這玩意兒究竟是哪兒冒出來的呢。

能夠看出來modules 裏面存放着的是foo模塊的內容,那這些內容是怎麼來的呢?經過foo的module.exports提供的啊。那麼modules裏面其實放的是,foo的module.exports。

而foo對於當前模塊來講是外部的模塊。而我想調用外面的東西,只有兩種辦法,要麼傳參數,要麼經過全局變量(不過或許大神還有其餘方案,我就只曉得這兩種了)。define裏面有的參數沒有一個是存放module.exports的。那麼答案呼之欲出了,modules是全局變量。

modules = {};
function load(id, exports) {
  (modules || (modules = {}))[id] = exports;
}

再來看看完整的代碼,變成啥樣了

modules = {};
function load(name, exports) {
  (modules || (modules = {}))[name] = exports;
}

define = function(id, deps, callback) {
  
  var require = function(name) {
    return modules[name] || {};
  }

  var module = {};
  var module.exports = exports = {};

  callback(require, exports, module);

  load(id, module.exports);
};

到如今差很少已經成型了,那麼這裏的require, exports, module都是外來的模塊吧bingo,其實callback裏的模塊都是根據deps來的,去掉require, exports, module

modules = {};
function load(name, exports) {
  (modules || (modules = {}))[name] = exports;
}

define = function(id, deps, callback) {
  
  // 至關於
  // var module = {};
  // var module.exports = {};
  var module = modules['module'];
  
  // 至關於
  //var require = function(name) {
  //  return modules[name] || {};
  //}
  var require = modules['require'];

  var args = deps.map(require);

  callback.apply(null, args);

  load(id, module.exports);
};

來看define的另外一種形式

define('alpha' ,['foo'], function(foo) {
  return function() {
    foo.doSomething();
  }
});

咦,精簡了很多誒。沒有exports了誒,會返回了麼

modules = {};
function load(name, exports) {
  (modules || (modules = {}))[name] = exports;
}

define = function(id, deps, callback) {
  
  var module = modules['module'];
  
  var require = modules['require'];

  var args = deps.map(require);

  var exports = callback.apply(null, args);

  load(id, exports || module.exports);
};

OK,先告一段落了,累死我丫了。在慢慢優化吧,唉。

參考(關於exports 和 module.exports 的區別)

exports 和 module.exports 的區別這篇文章很不賴。

人家大神已經說得很是好了。我在了淺薄的打個比方,我有個文件夾叫module.exports,而後我建立了一個超連接叫exports,那我在任何一個裏面操做最終都會反應到另外一個裏,但若是我把超連接exports刪了把它的指向地址改了,並不會影響真正的文件夾module.exports。

而有不少人明明已經改了超連接exports的指向地址(如:exports = 123;),再在超連接裏面作了不少操做(如:exports.hello = 456;),那都不會對真正的文件夾module.exports起到任何做用(你是見不到module.exports.hello === 456的)。

相關文章
相關標籤/搜索