请选择 进入手机版 | 继续访问电脑版

NodejQ

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2163|回复: 12

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

  [复制链接]
发表于 2017-10-8 21:34:20 | 显示全部楼层 |阅读模式
在Node.js中对模块载入和执行进行了包装,使得模块文件中的变量在一个闭包中,不会污染全局变量,和他人冲突。
前端模块通常是我们开发人员为了避免和他人冲突才把模块代码放置在一个闭包中。
如何封装Node.js和前端通用的模块,我们可以参考Underscore.js 实现,他就是一个Node.js和前端通用的功能函数模块,查看代码:
  1. // Create a safe reference to the Underscore object for use below.
  2.   var _ = function(obj) {
  3.     if (obj instanceof _) return obj;
  4.     if (!(this instanceof _)) return new _(obj);
  5.     this._wrapped = obj;
  6.   };
  7.   
  8.   // Export the Underscore object for **Node.js**, with
  9.   // backwards-compatibility for the old `require()` API. If we're in
  10.   // the browser, add `_` as a global object via a string identifier,
  11.   // for Closure Compiler "advanced" mode.
  12.   if (typeof exports !== 'undefined') {
  13.     if (typeof module !== 'undefined' && module.exports) {
  14.       exports = module.exports = _;
  15.     }
  16.     exports._ = _;
  17.   } else {
  18.     root._ = _;
  19.   }
复制代码
通过判断exports是否存在来决定将局部变量 _ 赋值给exports,向后兼容旧的require() API,如果在浏览器中,通过一个字符串标识符“_”作为一个全局对象;完整的闭包如下:
  1. (function() {
  2.   
  3.   // Baseline setup
  4.   // --------------
  5.   
  6.   // Establish the root object, `window` in the browser, or `exports` on the server.
  7.   var root = this;
  8.   
  9.   // Create a safe reference to the Underscore object for use below.
  10.   var _ = function(obj) {
  11.     if (obj instanceof _) return obj;
  12.     if (!(this instanceof _)) return new _(obj);
  13.     this._wrapped = obj;
  14.   };
  15.   
  16.   // Export the Underscore object for **Node.js**, with
  17.   // backwards-compatibility for the old `require()` API. If we're in
  18.   // the browser, add `_` as a global object via a string identifier,
  19.   // for Closure Compiler "advanced" mode.
  20.   if (typeof exports !== 'undefined') {
  21.     if (typeof module !== 'undefined' && module.exports) {
  22.       exports = module.exports = _;
  23.     }
  24.     exports._ = _;
  25.   } else {
  26.     root._ = _;
  27.   }
  28. }).call(this);
复制代码
通过function定义构建了一个闭包,call(this)是将function在this对象下调用,以避免内部变量污染到全局作用域。浏览器中,this指向的是全局对象(window对象),将“_”变量赋在全局对象上“root._”,以供外部调用。
和Underscore.js 类似的Lo-Dash,也是使用了类似的方案,只是兼容了AMD模块载入的兼容:
  1. ;(function() {
  2.   
  3.   /** Used as a safe reference for `undefined` in pre ES5 environments */
  4.   var undefined;
  5.     /** Used to determine if values are of the language type Object */
  6.       var objectTypes = {
  7.         'boolean': false,
  8.         'function': true,
  9.         'object': true,
  10.         'number': false,
  11.         'string': false,
  12.         'undefined': false
  13.       };
  14.   /** Used as a reference to the global object */
  15.   var root = (objectTypes[typeof window] && window) || this;
  16.   
  17.   /** Detect free variable `exports` */
  18.   var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
  19.   
  20.   /** Detect free variable `module` */
  21.   var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
  22.   
  23.   /** Detect the popular CommonJS extension `module.exports` */
  24.   var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
  25.   
  26. /*--------------------------------------------------------------------------*/
  27.   
  28.   // expose Lo-Dash
  29.   var _ = runInContext();
  30.   
  31.   // some AMD build optimizers, like r.js, check for condition patterns like the following:
  32.   if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
  33.     // Expose Lo-Dash to the global object even when an AMD loader is present in
  34.     // case Lo-Dash was injected by a third-party script and not intended to be
  35.     // loaded as a module. The global assignment can be reverted in the Lo-Dash
  36.     // module by its `noConflict()` method.
  37.     root._ = _;
  38.   
  39.     // define as an anonymous module so, through path mapping, it can be
  40.     // referenced as the "underscore" module
  41.     define(function() {
  42.       return _;
  43.     });
  44.   }
  45.   // check for `exports` after `define` in case a build optimizer adds an `exports` object
  46.   else if (freeExports && freeModule) {
  47.     // in Node.js or RingoJS
  48.     if (moduleExports) {
  49.       (freeModule.exports = _)._ = _;
  50.     }
  51.     // in Narwhal or Rhino -require
  52.     else {
  53.       freeExports._ = _;
  54.     }
  55.   }
  56.   else {
  57.     // in a browser or Rhino
  58.     root._ = _;
  59.   }
  60. }.call(this));
复制代码
再来看看Moment.js的封装闭包主要代码:
  1. (function (undefined) {
  2.     var moment;
  3.     // check for nodeJS
  4.     var hasModule = (typeof module !== 'undefined' && module.exports);
  5. /************************************
  6.         Exposing Moment
  7.     ************************************/
  8.   
  9.     function makeGlobal(deprecate) {
  10.         var warned = false, local_moment = moment;
  11.         /*global ender:false */
  12.         if (typeof ender !== 'undefined') {
  13.             return;
  14.         }
  15.         // here, `this` means `window` in the browser, or `global` on the server
  16.         // add `moment` as a global object via a string identifier,
  17.         // for Closure Compiler "advanced" mode
  18.         if (deprecate) {
  19.             this.moment = function () {
  20.                 if (!warned && console && console.warn) {
  21.                     warned = true;
  22.                     console.warn(
  23.                             "Accessing Moment through the global scope is " +
  24.                             "deprecated, and will be removed in an upcoming " +
  25.                             "release.");
  26.                 }
  27.                 return local_moment.apply(null, arguments);
  28.             };
  29.         } else {
  30.             this['moment'] = moment;
  31.         }
  32.     }
  33.   
  34.     // CommonJS module is defined
  35.     if (hasModule) {
  36.         module.exports = moment;
  37.         makeGlobal(true);
  38.     } else if (typeof define === "function" && define.amd) {
  39.         define("moment", function (require, exports, module) {
  40.             if (module.config().noGlobal !== true) {
  41.                 // If user provided noGlobal, he is aware of global
  42.                 makeGlobal(module.config().noGlobal === undefined);
  43.             }
  44.   
  45.             return moment;
  46.         });
  47.     } else {
  48.         makeGlobal();
  49.     }
  50. }).call(this);
复制代码
从上面的几个例子可以看出,在封装Node.js和前端通用的模块时,可以使用以下逻辑:
  1. if (typeof exports !== "undefined") {
  2.     exports.** = **;
  3. } else {
  4.     this.** = **;
  5. }
复制代码
即,如果exports对象存在,则将局部变量装载在exports对象上,如果不存在,则装载在全局对象上。如果加上ADM规范的兼容性,那么多加一句判断:
  1. if (typeof define === "function" && define.amd){}
复制代码


点击放大,扫码打赏,金额随意!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|NodejQ ( 粤ICP备18055488号 )

GMT+8, 2020-1-27 10:28 , Processed in 0.037382 second(s), 7 queries , Redis On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表