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 document.images实例
May 27 Javascript
JS的数组的扩展实例代码
Jul 09 Javascript
一个JavaScript的求爱小特效
May 09 Javascript
js数组与字符串的相互转换方法
Jul 09 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
Feb 14 Javascript
jquery获取复选框checkbox的值实现方法
May 30 Javascript
js实现select选择框效果及美化
Aug 19 Javascript
JS移动端/H5同时选择多张图片上传并使用canvas压缩图片
Jun 20 Javascript
js推箱子小游戏步骤代码解析
Jan 10 Javascript
vue.js+elementUI实现点击左右箭头切换头像功能(类似轮播图效果)
Sep 05 Javascript
react中hook介绍以及使用教程
Dec 11 Javascript
为什么node.js不适合大型项目
Apr 28 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的微信支付接口使用方法讲解
2019/03/08 PHP
WEB页子窗口(showModalDialog和showModelessDialog)使用说明
2009/10/25 Javascript
使用Jquery搭建最佳用户体验的登录页面之记住密码自动登录功能(含后台代码)
2011/07/10 Javascript
javascript验证身份证完全方法具体实现
2013/11/18 Javascript
超级好用的jQuery圆角插件 Corner速成
2014/08/31 Javascript
jquery delay()介绍及使用指南
2014/09/02 Javascript
javascript 操作符(~、&、|、^、)使用案例
2014/12/31 Javascript
JavaScript中的replace()方法使用详解
2015/06/06 Javascript
javascript实现网页子页面遍历回调的方法(涉及 window.frames、递归函数、函数上下文)
2015/07/27 Javascript
基于Phantomjs生成PDF的实现方法
2016/11/07 Javascript
概述javascript在Google IE中的调试技巧
2016/11/24 Javascript
JS多物体实现缓冲运动效果示例
2016/12/20 Javascript
JS去掉字符串前后空格或去掉所有空格的用法
2017/03/25 Javascript
js获取指定时间的前几秒
2017/04/05 Javascript
JS如何设置元素样式的方法示例
2017/08/28 Javascript
深入Vue-Router路由嵌套理解
2018/08/13 Javascript
JS 验证码功能的三种实现方式
2018/11/26 Javascript
JavaScript的级联函数用法简单示例【链式调用】
2019/03/26 Javascript
基于elementUI使用v-model实现经纬度输入的vue组件
2019/05/12 Javascript
vue获取data数据改变前后的值方法
2019/11/07 Javascript
jquery添加div实现消息聊天框
2020/02/08 jQuery
vue+高德地图实现地图搜索及点击定位操作
2020/09/09 Javascript
Python中的pprint折腾记
2015/01/21 Python
举例讲解Python设计模式编程的代理模式与抽象工厂模式
2016/01/16 Python
python中pika模块问题的深入探究
2018/10/13 Python
selenium+python自动化测试之页面元素定位
2019/01/23 Python
详解Python下载图片并保存本地的两种方式
2019/05/15 Python
python常用排序算法的实现代码
2019/11/08 Python
Python 类的魔法属性用法实例分析
2019/11/21 Python
pycharm设置当前工作目录的操作(working directory)
2020/02/14 Python
汽车机修工岗位职责
2014/03/06 职场文书
群众路线教育实践活动心得体会
2014/03/07 职场文书
中学校庆方案
2014/03/17 职场文书
毕业生学校推荐信范文
2014/05/21 职场文书
2015年乡镇残联工作总结
2015/05/13 职场文书
订货会主持词
2015/07/01 职场文书