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 相关文章推荐
JavaScript取得鼠标绝对位置程序代码介绍
Sep 16 Javascript
上传图片预览JS脚本 Input file图片预览的实现示例
Oct 23 Javascript
ECMA5数组的新增方法有哪些及forEach()模仿实现
Nov 03 Javascript
JS代码随机生成姓名、手机号、身份证号、银行卡号
Apr 27 Javascript
JS定义类的六种方式详解
May 12 Javascript
JS闭包与延迟求值用法示例
Dec 22 Javascript
用director.js实现前端路由使用实例
Jan 27 Javascript
JQ中$(window).load和$(document).ready区别与执行顺序
Mar 01 Javascript
Layui table 组件的使用之初始化加载数据、数据刷新表格、传参数
Sep 11 Javascript
javascript trie前缀树的示例
Jan 29 Javascript
详解mpvue中小程序自定义导航组件开发指南
Feb 11 Javascript
Element Tooltip 文字提示的使用示例
Jul 26 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
《PHP编程最快明白》第四讲:日期、表单接收、session、cookie
2010/11/01 PHP
PHP中for与foreach的区别分析
2011/03/09 PHP
php 随机排序广告的实现代码
2011/05/09 PHP
php中使用addslashes函数报错问题的解决方法
2013/02/06 PHP
php定时计划任务的实现方法详解
2013/06/06 PHP
PHP+FFMPEG实现将视频自动转码成H264标准Mp4文件
2014/09/24 PHP
ThinkPHP框架搭建及常见问题(XAMPP安装失败、Apache/MySQL启动失败)
2016/04/15 PHP
PHP实现的简单对称加密与解密方法实例小结
2017/08/28 PHP
6个DIV 135或246间隔一秒轮番显示效果
2010/07/24 Javascript
基于jQuery的message插件实现右下角弹出消息框
2011/01/11 Javascript
关于img的href和src取变量及赋值的方法
2014/04/28 Javascript
jQuery实现的多选框多级联动插件
2014/05/02 Javascript
9款2014最热门jQuery实用特效推荐
2014/12/07 Javascript
js实现鼠标移到链接文字弹出一个提示层的方法
2015/05/11 Javascript
javascript实现十秒钟后注册按钮可点击的方法
2015/05/13 Javascript
小议JavaScript中Generator和Iterator的使用
2015/07/29 Javascript
微信小程序 石头剪刀布实例代码
2017/01/04 Javascript
JS作用域链详解
2017/06/26 Javascript
Angular4.0中引入laydate.js日期插件的方法教程
2017/12/25 Javascript
vue select二级联动第二级默认选中第一个option值的实例
2018/01/10 Javascript
vue实现城市列表选择功能
2018/07/16 Javascript
浅谈React之状态(State)
2018/09/19 Javascript
webpack的 rquire.context用法实现工程自动化的方法
2020/02/07 Javascript
js中火星坐标、百度坐标、WGS84坐标转换实现方法示例
2020/03/02 Javascript
Python中多线程thread与threading的实现方法
2014/08/18 Python
Python的高级Git库 Gittle
2014/09/22 Python
Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程
2014/11/18 Python
Python中的类与对象之描述符详解
2015/03/27 Python
Python的SQLalchemy模块连接与操作MySQL的基础示例
2016/07/11 Python
分析运行中的 Python 进程详细解析
2019/06/22 Python
应用OpenCV和Python进行SIFT算法的实现详解
2019/08/21 Python
python解析yaml文件过程详解
2019/08/30 Python
python+flask编写一个简单的登录接口
2020/11/13 Python
新西兰网上购物,折扣店:BestDeals.co.nz
2019/03/20 全球购物
优秀教师单行材料
2014/12/16 职场文书
寻找成龙观后感
2015/06/12 职场文书