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 相关文章推荐
jQuery Flash/MP3/Video多媒体插件
Jan 18 Javascript
JS实现self的resend
Jul 22 Javascript
jsp+javascript打造级连菜单的实例代码
Jun 14 Javascript
5秒后跳转到另一个页面的js代码
Oct 12 Javascript
JScript中的条件注释详解
Apr 24 Javascript
jQuery如何跳转到另一个网页 就这么简单
Dec 28 Javascript
基于Vue实现拖拽效果
Apr 27 Javascript
微信小程序实现自上而下字幕滚动
Jul 14 Javascript
利用Promise自定义一个GET请求的函数示例代码
Mar 20 Javascript
Vue开发环境中修改端口号的实现方法
Aug 15 Javascript
JS实现手写 forEach算法示例
Apr 29 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
May 12 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
一个颜色轮换的简单例子
2006/10/09 PHP
让PHP支持断点续传的源码
2010/05/16 PHP
从PHP $_SERVER相关参数判断是否支持Rewrite模块
2013/09/26 PHP
PHP使用DOM对XML解析处理操作示例
2019/07/04 PHP
JQuery 绑定事件时传递参数的实现方法
2009/10/13 Javascript
基于Jquery的简单图片切换效果
2011/01/06 Javascript
jQuery.validate 常用方法及需要注意的问题
2013/03/20 Javascript
nodejs中简单实现Javascript Promise机制的实例
2014/12/06 NodeJs
老生常谈JQuery data方法的使用
2016/09/09 Javascript
jQuery图片前后对比插件beforeAfter用法示例【附demo源码下载】
2016/09/20 Javascript
bootstrap学习使用(导航条、下拉菜单、轮播、栅格布局等)
2016/12/01 Javascript
详解在React-Native中持久化redux数据
2019/05/22 Javascript
[02:17]《辉夜杯》TRG战队巡礼
2015/10/26 DOTA
Python基础之函数用法实例详解
2014/09/10 Python
Python HTMLParser模块解析html获取url实例
2015/04/08 Python
python列表的增删改查实例代码
2018/01/30 Python
Ubuntu16.04/树莓派Python3+opencv配置教程(分享)
2018/04/02 Python
Python基于聚类算法实现密度聚类(DBSCAN)计算【测试可用】
2018/12/26 Python
Python常用的json标准库
2019/02/19 Python
Python判断两个文件是否相同与两个文本进行相同项筛选的方法
2019/03/01 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
2019/11/11 Python
Python 实现将数组/矩阵转换成Image类
2020/01/09 Python
CSS3属性选择符介绍
2008/10/17 HTML / CSS
html5指南-2.如何操作document metadata
2013/01/07 HTML / CSS
中学教师管理制度
2014/01/14 职场文书
12岁生日感言
2014/01/21 职场文书
法学毕业生自我鉴定
2014/01/31 职场文书
九年级政治教学反思
2014/02/06 职场文书
报关员个人职业生涯规划书
2014/03/12 职场文书
物理系毕业生自荐书
2014/06/13 职场文书
五五普法心得体会
2014/09/04 职场文书
党员违纪检讨书怎么写
2014/11/01 职场文书
房地产公司财务总监岗位职责
2015/04/03 职场文书
2016同学毕业寄语大全
2015/12/04 职场文书
如何使用Python对NetCDF数据做空间相关分析
2021/04/21 Python
浅谈Python数学建模之整数规划
2021/06/23 Python