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 相关文章推荐
JS弹出对话框返回值代码(asp.net后台)
Dec 28 Javascript
通过jquery的$.getJSON做一个跨域ajax请求试验
May 03 Javascript
网页收藏夹显示ICO图标(代码少)
Aug 04 Javascript
使用requestAnimationFrame实现js动画性能好
Aug 06 Javascript
Bootstrap实现响应式导航栏效果
Dec 28 Javascript
多个js毫秒倒计时同时进行效果
Jan 05 Javascript
javascript计时器编写过程与实现方法
Feb 29 Javascript
Jquery实现上下移动和排序代码
Oct 17 Javascript
Bootstrap基本组件学习笔记之面板(14)
Dec 08 Javascript
node链接mongodb数据库的方法详解【阿里云服务器环境ubuntu】
Mar 07 Javascript
详解Vue-Router源码分析路由实现原理
May 15 Javascript
原生js实现商品筛选功能
Oct 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
如何解决CI框架的Disallowed Key Characters错误提示
2013/07/05 PHP
利用PHP计算有多少小于当前数字的数字方法示例
2020/08/26 PHP
javaScript 计算两个日期的天数相差(示例代码)
2013/12/27 Javascript
JS实现自动定时切换的简洁网页选项卡效果
2015/10/13 Javascript
JavaScript中Boolean对象的属性解析
2015/10/21 Javascript
javascript动态添加checkbox复选框的方法
2015/12/23 Javascript
js修改onclick动作的四种方法(推荐)
2016/08/18 Javascript
微信小程序 详解下拉加载与上拉刷新实现方法
2017/01/13 Javascript
NodeJS遍历文件生产文件列表功能示例
2017/01/22 NodeJs
AngularJs每天学习之总体介绍
2017/08/07 Javascript
vue动态绑定组件子父组件多表单验证功能的实现代码
2018/05/14 Javascript
vue.extend与vue.component的区别和联系
2018/09/19 Javascript
vue-router实现嵌套路由的讲解
2019/01/19 Javascript
基于Vue 实现一个中规中矩loading组件
2019/04/03 Javascript
JS常用正则表达式超全集(密码强度校验,金额校验,IE版本,IPv4,IPv6校验)
2020/02/03 Javascript
vue cli4下环境变量和模式示例详解
2020/04/09 Javascript
vue 使用post/get 下载导出文件操作
2020/08/07 Javascript
[01:31](回顾)杀出重围,决战TI之巅
2014/07/01 DOTA
[58:37]Serenity vs Fnatic 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
python黑魔法之参数传递
2016/02/12 Python
Python编程实战之Oracle数据库操作示例
2017/06/21 Python
python读取一个目录下所有txt里面的内容方法
2018/06/23 Python
anaconda如何查看并管理python环境
2019/07/05 Python
Django后台管理系统的图文使用教学
2020/01/20 Python
CSS3 transform的skew属性值图文详解
2014/07/21 HTML / CSS
Eton丹麦官网:精美的男式衬衫
2020/05/27 全球购物
活动志愿者自荐信
2014/01/27 职场文书
《山谷中的谜底》教学反思
2014/04/26 职场文书
关于读书的活动方案
2014/08/14 职场文书
助人为乐道德模范事迹材料
2014/08/16 职场文书
房产授权委托书范本
2014/09/22 职场文书
杭州西湖英语导游词
2015/02/03 职场文书
单位政审意见范文
2015/06/04 职场文书
换届选举主持词
2015/07/03 职场文书
幽默导游词应该怎么写?
2019/08/26 职场文书
2019年暑期法院实习报告
2019/12/18 职场文书