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 相关文章推荐
Google Map Api和GOOGLE Search Api整合实现代码
Jul 18 Javascript
js 纯数字不重复排列的另类方法
Jul 17 Javascript
javascript实现促销倒计时+fixed固定在底部
Sep 18 Javascript
jquery马赛克拼接翻转效果代码分享
Aug 24 Javascript
AngularJS控制器继承自另一控制器
May 09 Javascript
实现React单页应用的方法详解
Aug 02 Javascript
JS基于正则表达式的替换操作(replace)用法示例
Apr 28 Javascript
使用Node.js实现ORM的一种思路详解(图文)
Oct 24 Javascript
微信小程序录音与播放录音功能
Dec 25 Javascript
Vue仿支付宝支付功能
May 25 Javascript
微信小程序日历效果
Dec 29 Javascript
使用apifm-wxapi快速开发小程序过程详解
Aug 05 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报错configure error Cannot find libmysqlclient under usr的解决方法
2014/06/27 PHP
CodeIgniter配置之config.php用法实例分析
2016/01/19 PHP
Gambit vs CL BO3 第三场 2.13
2021/03/10 DOTA
javascript AutoScroller 函数类
2009/05/29 Javascript
JQuery 无废话系列教程(二) jquery实战篇上
2009/06/23 Javascript
使用滤镜设置透明导致 IE 6/7/8/9 解析异常的解决方法
2011/04/07 Javascript
js 页面关闭前的出现提示的实现代码
2011/05/25 Javascript
关于递归运算的顺序测试代码
2011/11/30 Javascript
jQuery实现提示密码强度的代码
2015/07/15 Javascript
Javascript实现可旋转的圆圈实例代码
2015/08/04 Javascript
jQuery设置单选按钮radio选中/不可用的实例代码
2016/06/24 Javascript
Seajs是什么及sea.js 由来,特点以及优势
2016/10/13 Javascript
js导出excel文件的简洁方法(推荐)
2016/11/02 Javascript
AngularJs验证重复密码的方法(两种)
2016/11/25 Javascript
JS实现动态修改table及合并单元格的方法示例
2017/02/20 Javascript
JavaScript下拉菜单功能实例代码
2017/03/01 Javascript
angular.JS实现网页禁用调试、复制和剪切
2017/03/31 Javascript
使用javaScript实现鼠标拖拽事件
2020/04/03 Javascript
vue里面使用mui的弹出日期选择插件实例
2018/09/16 Javascript
Vue-drag-resize 拖拽缩放插件的使用(简单示例)
2019/12/04 Javascript
基于vue-cli3创建libs库的实现方法
2019/12/04 Javascript
React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析
2020/01/06 Javascript
[00:44]华丽开场!DOTA2勇士令状带来全新对阵画面
2019/05/15 DOTA
python 借助numpy保存数据为csv格式的实现方法
2018/07/04 Python
pytorch实现seq2seq时对loss进行mask的方式
2020/02/18 Python
基于Python爬取爱奇艺资源过程解析
2020/03/02 Python
基础的CSS3弹性盒Flexbox布局使用实例
2016/04/08 HTML / CSS
凌阳科技股份有限公司C++程序员面试题笔试题
2014/11/20 面试题
医院实习接收函
2014/01/12 职场文书
幼儿园校车司机的岗位职责
2014/01/30 职场文书
《北大荒的秋天》教学反思
2014/04/14 职场文书
设计大赛策划方案
2014/06/13 职场文书
顶岗实习协议书
2015/01/29 职场文书
酒店前台岗位职责
2015/04/16 职场文书
元旦联欢晚会主持词
2015/07/01 职场文书
flex弹性布局详解
2022/03/20 HTML / CSS