您的位置:首页 > Web前端 > Node.js

如何封装Node.js和前端通用的模块

2013-11-21 10:33 676 查看
在Node.js中对模块载入和执行进行了包装,使得模块文件中的变量在一个闭包中,不会污染全局变量,和他人冲突。

前端模块通常是我们开发人员为了避免和他人冲突才把模块代码放置在一个闭包中。

如何封装Node.js和前端通用的模块,我们可以参考Underscore.js 实现,他就是一个Node.js和前端通用的功能函数模块,查看代码:

12345678910111213141516171819// Create a safe reference to the Underscore object for use below. var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; }; // Export the Underscore object for **Node.js**, with // backwards-compatibility for the old `require()` API. If we're in // the browser, add `_` as a global object via a string identifier, // for Closure Compiler "advanced" mode. if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = _; } exports._ = _; } else { root._ = _; }
通过判断exports是否存在来决定将局部变量 _ 赋值给exports,向后兼容旧的
require()
API,如果在浏览器中,通过一个字符串标识符“_”作为一个全局对象;完整的闭包如下:

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

(function()
{

//
Baseline setup

//
--------------

//
Establish the root object, `window` in the browser, or `exports` on the server.

var
root
=
this;

//
Create a safe reference to the Underscore object for use below.

var
_
=
function(obj)
{

if
(obj
instanceof
_)
return
obj;

if
(!(this
instanceof
_))
return
new
_(obj);

this._wrapped
=
obj;

};

//
Export the Underscore object for **Node.js**, with

//
backwards-compatibility for the old `require()` API. If we're in

//
the browser, add `_` as a global object via a string identifier,

//
for Closure Compiler "advanced" mode.

if
(typeof
exports
!==
'undefined')
{

if
(typeof
module
!==
'undefined'
&&
module.exports)
{

exports
=
module.exports
=
_;

}

exports._
=
_;

}
else
{

root._
=
_;

}

}).call(this);

通过function定义构建了一个闭包,call(this)是将function在this对象下调用,以避免内部变量污染到全局作用域。浏览器中,this指向的是全局对象(window对象),将“_”变量赋在全局对象上“root._”,以供外部调用。

和Underscore.js 类似的Lo-Dash,也是使用了类似的方案,只是兼容了AMD模块载入的兼容:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960;(function() { /** Used as a safe reference for `undefined` in pre ES5 environments */ var undefined; /** Used to determine if values are of the language type Object */ var objectTypes = { 'boolean': false, 'function': true, 'object': true, 'number': false, 'string': false, 'undefined': false }; /** Used as a reference to the global object */ var root = (objectTypes[typeof window] && window) || this; /** Detect free variable `exports` */ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; /** Detect free variable `module` */ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; /** Detect the popular CommonJS extension `module.exports` */ var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; /*--------------------------------------------------------------------------*/ // expose Lo-Dash var _ = runInContext(); // some AMD build optimizers, like r.js, check for condition patterns like the following: if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // Expose Lo-Dash to the global object even when an AMD loader is present in // case Lo-Dash was injected by a third-party script and not intended to be // loaded as a module. The global assignment can be reverted in the Lo-Dash // module by its `noConflict()` method. root._ = _; // define as an anonymous module so, through path mapping, it can be // referenced as the "underscore" module define(function() { return _; }); } // check for `exports` after `define` in case a build optimizer adds an `exports` object else if (freeExports && freeModule) { // in Node.js or RingoJS if (moduleExports) { (freeModule.exports = _)._ = _; } // in Narwhal or Rhino -require else { freeExports._ = _; } } else { // in a browser or Rhino root._ = _; }}.call(this));
再来看看Moment.js的封装闭包主要代码:

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

(function
(undefined)
{

var
moment;

//
check for nodeJS

var
hasModule
=
(typeof
module
!==
'undefined'
&&
module.exports);

/************************************

Exposing Moment

************************************/

function
makeGlobal(deprecate)
{

var
warned
=
false,
local_moment
=
moment;

/*global
ender:false */

if
(typeof
ender
!==
'undefined')
{

return;

}

//
here, `this` means `window` in the browser, or `global` on the server

//
add `moment` as a global object via a string identifier,

//
for Closure Compiler "advanced" mode

if
(deprecate)
{

this.moment
=
function
()
{

if
(!warned
&&
console
&&
console.warn)
{

warned
=
true;

console.warn(

"Accessing
Moment through the global scope is "
+

"deprecated,
and will be removed in an upcoming "
+

"release.");

}

return
local_moment.apply(null,
arguments);

};

}
else
{

this['moment']
=
moment;

}

}

//
CommonJS module is defined

if
(hasModule)
{

module.exports
=
moment;

makeGlobal(true);

}
else
if
(typeof
define
===
"function"
&&
define.amd)
{

define("moment",
function
(require,
exports,
module)
{

if
(module.config().noGlobal
!==
true)
{

//
If user provided noGlobal, he is aware of global

makeGlobal(module.config().noGlobal
===
undefined);

}

return
moment;

});

}
else
{

makeGlobal();

}

}).call(this);

从上面的几个例子可以看出,在封装Node.js和前端通用的模块时,可以使用以下逻辑:

12345if (typeof exports !== "undefined") { exports.** = **;} else { this.** = **;}
即,如果exports对象存在,则将局部变量装载在exports对象上,如果不存在,则装载在全局对象上。如果加上ADM规范的兼容性,那么多加一句判断:

1

if
(typeof
define
===
"function"
&&
define.amd){}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: