天天看點

讀RequireJS — Module

Module 即子產品,來看下RequireJS怎麼定義 Module :

1. 簡單的名值對

?

// Inside file my/shirt.js:

define({

color:

"black"

,

size:

"unisize"

});

2. 定義成一個Function

// my/shirt.js now does setup work

// before returning its module definition.

define(

function

() {

// Do setup work here

return

{

color:

"black"

,

size:

"unisize"

}

});

3. 如果 Module 需要依賴别的子產品,可以寫成這樣:

// my/shirt.js now has some dependencies, a cart and inventory

// module in the same directory as shirt.js

define([

"./cart"

,

"./inventory"

],

function

(cart, inventory) {

// return an object to define the "my/shirt" module.

return

{

color:

"blue"

,

size:

"large"

,

addToCart:

function

() {

inventory.decrement(

this

);

cart.add(

this

);

}

}

}

);

4. 隐式依賴Function

define(

function

(require) {

var

mod = require(

"./relative/name"

);

});

  

上面這四種比較常用,RequireJS 中的 Module 還有其他的形式,具體可參閱官方文檔。

上面四種方式都用到了define(),接下來我們就來看下define的源碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

/**

* The function that handles definitions of modules. Differs from

* require() in that a string for the module should be the first argument,

* and the function to execute after dependencies are loaded should

* return a value to define the module corresponding to the first argument's

* name.

*/

define =

function

(name, deps, callback) {

var

node, context;

// 可以是匿名子產品

if

(

typeof

name !== 'string') {

// 調整參數

callback = deps;

deps = name;

name =

null

;

}

// 如果子產品沒有依賴

if

(!isArray(deps)) {

callback = deps;

deps = [];

}

// 如果是一個沒有傳入依賴的Function,即例4所示

if

(!deps.length && isFunction(callback)) {

// 通過 callback.toString() 找依賴

// 為了避免 require(xx) 寫在注釋中

// 這裡先把注釋都去掉,再把require的東東加入deps數組

//

// 很變态的一點就是如果callback裡寫了require

// 則 callback 必須有形參,不然會被無視

if

(callback.length) {

callback

.toString()

.replace(commentRegExp,

""

)

.replace(cjsRequireRegExp,

function

(match, dep) {

deps.push(dep);

});

//May be a CommonJS thing even without require calls, but still

//could use exports, and module. Avoid doing exports and module

//work though if it just needs require.

//REQUIRES the function to expect the CommonJS variables in the

//order listed below.

// 可能某些子產品即使沒有調用require,但卻仍然要用到exports和module

// 如果子產品僅僅需要require,就應該避免exports和module的開銷

// 注意:依賴的順序應該確定像下面這樣

//

// 這裡我把中英文都給出了,因為對于這句我一直很疑惑

// 1個形參 需要 require

// 大于1個形參 需要 require exports module

// 1和非1有那麼大差别麼,請高手指點一下,這句實在很無解

deps = (callback.length === 1 ? [

"require"

] : [

"require"

,

"exports"

,

"module"

]).concat(deps);

}

}

// 應用場景:IE6-8,并且是定義一個匿名子產品

// 個人覺得這個判斷沒有意義,請看下面的注釋

if

(useInteractive) {

node = currentlyAddingScript || getInteractiveScript();

if

(node) {

if

(!name) {

name = node.getAttribute(

"data-requiremodule"

);

}

context = contexts[node.getAttribute(

"data-requirecontext"

)];

}

}

// 真正定義子產品的操作放到script onload函數中執行,有兩個好處:

// 1.如果一個檔案定義了多個子產品,這樣可以防止過早的分析依賴, 而是等拿到所有依賴之後, 統一進行處理

// 2.如果是定義匿名子產品, define執行中我們是不知道 moduleName的, 但在onload函數中卻可以知道

//

// 這裡有個問題,即下面這行代碼表示有context就加入context.defQueue,沒有就加入globalDefQueue

// 很明顯,context有值的情況僅在IE6-8會出現,

// 而在onload時,會把globalDefQueue裡的東西全部加入context.defQueue,是以加入誰無所謂

// 而且在onload函數中所有浏覽器都可以拿到moduleName,是以下面這句和上面那個if判斷都失去意義了

// 可以寫成 globalDefQueue.push([name, deps, callback]);

(context ? context.defQueue : globalDefQueue).push([name, deps, callback]);

return

undefined;

};

define() 有三個參數,不傳 name 參數表示為匿名子產品,匿名隻是寫法上的匿名,RequireJS 可以通過檔案路徑确定 moduleName,是以最好别傳 name 參數,這樣檔案目錄即使有變動,也不會影響子產品的正常使用。

這裡 callback 參數命名很不好,一般都會叫做factory,取名 callback 完全不知所雲。  

所謂的 define 是幹嘛的呢 ?

繼續閱讀