Node.js中对通用模块的封装方法


Posted in Javascript onJune 06, 2014

在Node.js中对模块载入和执行进行了包装,使得模块文件中的变量在一个闭包中,不会污染全局变量,和他人冲突。

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

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

 
// 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,如果在浏览器中,通过一个字符串标识符“_”作为一个全局对象;完整的闭包如下:
(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模块载入的兼容:

 
;(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的封装闭包主要代码:
 
(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和前端通用的模块时,可以使用以下逻辑:
 
if (typeof exports !== "undefined") {
    exports.** = **;
} else {
    this.** = **;
}

即,如果exports对象存在,则将局部变量装载在exports对象上,如果不存在,则装载在全局对象上。如果加上ADM规范的兼容性,那么多加一句判断:
if (typeof define === "function" && define.amd){}
Javascript 相关文章推荐
百度Popup.js弹出框进化版 拖拽小框架发布 兼容IE6/7/8,Firefox,Chrome
Apr 13 Javascript
Javascript 中的 && 和 || 使用小结
Apr 25 Javascript
Javascript之旅 对象的原型链之由来
Aug 25 Javascript
js调试工具Console命令详解
Oct 21 Javascript
详解JS函数重载
Dec 04 Javascript
AngularJS的内置过滤器详解
May 14 Javascript
JS实现淘宝支付宝网站的控制台菜单效果
Sep 28 Javascript
bootstrap如何让dropdown menu按钮式下拉框长度一致
Apr 10 Javascript
canvas+gif.js打造自己的数字雨头像的示例代码
Oct 26 Javascript
JS二分查找算法详解
Nov 01 Javascript
element-ui组件中input等的change事件中传递自定义参数
May 22 Javascript
vue element-ui中table合计指定列求和实例
Nov 02 Javascript
JavaScript中对循环语句的优化技巧深入探讨
Jun 06 #Javascript
jquery修改网页背景颜色通过css方法实现
Jun 06 #Javascript
jquery动态调整div大小使其宽度始终为浏览器宽度
Jun 06 #Javascript
JavaScript也谈内存优化
Jun 06 #Javascript
Javascript中的delete操作符详细介绍
Jun 06 #Javascript
Javascript的严格模式strict mode详细介绍
Jun 06 #Javascript
jQuery实现购物车多物品数量的加减+总价计算
Jun 06 #Javascript
You might like
解决了Ajax、MySQL 和 Zend Framework 的乱码问题
2009/03/03 PHP
php过滤html标记属性类用法实例
2014/09/23 PHP
将FCKeditor导入PHP+SMARTY的实现方法
2015/01/15 PHP
PHP使用CURL实现下载文件功能示例
2019/06/03 PHP
jQuery 阴影插件代码分享
2012/01/09 Javascript
js中方法重载如何实现?以及函数的参数问题
2013/08/01 Javascript
jquery的trigger和triggerHandler的区别示例介绍
2014/04/20 Javascript
Jquery自定义button按钮的几种方法
2014/06/11 Javascript
浅析javascript操作 cookie对象
2014/12/26 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
2015/07/27 Javascript
jquery图片轮播特效代码分享
2020/04/20 Javascript
JavaScript中的原型prototype完全解析
2016/05/10 Javascript
JS实现页面载入时随机显示图片效果
2016/09/07 Javascript
jQuery中常用动画效果函数(日常整理)
2016/09/17 Javascript
微信小程序 开发工具快捷键整理
2016/10/31 Javascript
input输入密码变黑点密文的实现方法
2017/01/09 Javascript
微信小程序模拟cookie的实现
2018/06/20 Javascript
JavaScript 中 JSON.parse 函数 和 JSON.stringify 函数
2018/12/05 Javascript
微信小程序实现左侧滑动导航栏
2020/04/08 Javascript
Vue使用axios引起的后台session不同操作
2020/08/14 Javascript
小程序实现密码输入框
2020/11/16 Javascript
[51:14]LGD vs VP 2018国际邀请赛淘汰赛BO3 第一场 8.21
2018/08/22 DOTA
Python基于select实现的socket服务器
2016/04/13 Python
Python 文件处理注意事项总结
2017/04/10 Python
用python建立两个Y轴的XY曲线图方法
2019/07/08 Python
三步解决python PermissionError: [WinError 5]拒绝访问的情况
2020/04/22 Python
护理专业毕业生自我鉴定总结
2014/03/24 职场文书
资助贫困学生倡议书
2014/05/16 职场文书
反腐倡廉演讲稿
2014/05/22 职场文书
市场营销专业自荐书
2014/06/10 职场文书
环保志愿者活动总结
2014/06/27 职场文书
三好学生先进事迹材料
2014/08/28 职场文书
廉政教育的心得体会
2014/09/01 职场文书
实名检举信范文
2015/03/02 职场文书
学校学期工作总结
2015/08/13 职场文书
大学生先进个人主要事迹材料
2015/11/04 职场文书