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 自定义个性下拉选择框示例
Aug 20 Javascript
多种方式实现JS调用后台方法进行数据交互
Aug 20 Javascript
javascript自定义函数参数传递为字符串格式
Jul 29 Javascript
javascript实现网页端解压并查看zip文件
Dec 15 Javascript
jquery捕捉回车键及获取checkbox值与异步请求的方法
Dec 24 Javascript
AngularJS 使用$sce控制代码安全检查
Jan 05 Javascript
jQuery动画效果实现图片无缝连续滚动
Jan 12 Javascript
Bootstrap modal只加载一次数据的解决办法(推荐)
Nov 24 Javascript
JavaScript捕捉事件和阻止冒泡事件实例分析
Aug 03 Javascript
用node撸一个监测复联4开售短信提醒的实现代码
Apr 10 Javascript
VUE+elementui面包屑实现动态路由详解
Nov 04 Javascript
详细聊聊浏览器是如何看闭包的
Nov 11 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 5.3.0 安装分析心得
2009/08/07 PHP
php 无法加载mysql的module的时候的配置的解决方案引发的思考
2012/01/27 PHP
PHP中大括号'{}'用法实例总结
2017/02/08 PHP
PHP排序算法之简单选择排序(Simple Selection Sort)实例分析
2018/04/20 PHP
PHP 枚举类型的管理与设计知识点总结
2020/02/13 PHP
jquery.ui.draggable中文文档
2009/11/24 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
JavaScript中的console.time()函数详细介绍
2014/12/29 Javascript
Javascript常用小技巧汇总
2015/06/24 Javascript
详解webpack + vue + node 打造单页面(入门篇)
2017/09/23 Javascript
浅谈Node Inspector 代理实现
2017/10/19 Javascript
LayUI数据接口返回实体封装的例子
2019/09/12 Javascript
JS 遍历 json 和 JQuery 遍历json操作完整示例
2019/11/11 jQuery
深入分析JavaScript 事件循环(Event Loop)
2020/06/19 Javascript
使用python BeautifulSoup库抓取58手机维修信息
2013/11/21 Python
浅谈django model的get和filter方法的区别(必看篇)
2017/05/23 Python
Python使用文件锁实现进程间同步功能【基于fcntl模块】
2017/10/16 Python
Python使用requests发送POST请求实例代码
2018/01/25 Python
如何使用 Pylint 来规范 Python 代码风格(来自IBM)
2018/04/06 Python
python 常用的基础函数
2018/07/10 Python
Python实现数据可视化看如何监控你的爬虫状态【推荐】
2018/08/10 Python
Python用61行代码实现图片像素化的示例代码
2018/12/10 Python
pandas去除重复列的实现方法
2019/01/29 Python
Python-ElasticSearch搜索查询的讲解
2019/02/25 Python
python原类、类的创建过程与方法详解
2019/07/19 Python
Python建造者模式案例运行原理解析
2020/06/29 Python
Idea安装python显示无SDK问题解决方案
2020/08/12 Python
阿根廷网上配眼镜:SmartBuyGlasses阿根廷
2016/08/19 全球购物
澳大利亚首屈一指的在线购物目的地:Kogan.com
2017/02/02 全球购物
党员检讨书范文
2014/12/27 职场文书
个人工作保证书
2015/02/28 职场文书
部门经理助理岗位职责
2015/04/13 职场文书
高中升旗仪式主持词
2015/07/03 职场文书
2015年暑期实践报告范文
2015/07/13 职场文书
励志语录:你若不勇敢,谁替你坚强
2019/11/08 职场文书
Java网络编程之UDP实现原理解析
2021/09/04 Java/Android