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 相关文章推荐
基于jquery的finkyUI插件与Ajax实现页面数据加载功能
Dec 03 Javascript
JavaScript实现页面实时显示当前时间的简单实例
Jul 20 Javascript
js中replace的用法总结
Dec 27 Javascript
Javascript数组与字典用法分析
Dec 13 Javascript
js实现双击图片放大单击缩小的方法
Feb 17 Javascript
实例讲解JS中setTimeout()的用法
Jan 28 Javascript
AngularJs学习第五篇从Controller控制器谈谈$scope作用域
Jun 08 Javascript
vue.js移动数组位置,同时更新视图的方法
Mar 08 Javascript
浅谈vuex中store的命名空间
Nov 08 Javascript
js构造函数constructor和原型prototype原理与用法实例分析
Mar 02 Javascript
解决ant-design-vue中menu菜单无法默认展开的问题
Oct 31 Javascript
React + Threejs + Swiper 实现全景图效果的完整代码
Jun 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
探讨GDFONTPATH能否被winxp下的php支持
2013/06/21 PHP
thinkPHP通用控制器实现方法示例
2017/11/23 PHP
ajax请求get与post的区别总结
2013/11/04 Javascript
jquery库或JS文件在eclipse下报错问题解决方法
2014/04/17 Javascript
如何防止回车(enter)键提交表单
2014/05/11 Javascript
原生javascript实现的分页插件pagenav
2014/08/28 Javascript
基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架
2014/09/26 NodeJs
js实现鼠标滑过文字链接色彩变化的效果
2015/05/06 Javascript
简介AngularJS中使用factory和service的方法
2015/06/17 Javascript
JS设置cookie、读取cookie
2016/02/24 Javascript
JavaScript实现Java中Map容器的方法
2016/10/09 Javascript
jQuery 的 ready()的纯js替代方法
2016/11/20 Javascript
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
2018/08/09 jQuery
利用原生的JavaScript实现简单拼图游戏
2018/11/18 Javascript
Nodejs中怎么实现函数的串行执行
2019/03/02 NodeJs
vue中使用element组件时事件想要传递其他参数的问题
2019/09/18 Javascript
react-intl实现React国际化多语言的方法
2020/09/27 Javascript
[03:03]2014DOTA2西雅图国际邀请赛 Alliance战队巡礼
2014/07/07 DOTA
Python 第一步 hello world
2009/09/25 Python
用PyQt进行Python图形界面的程序的开发的入门指引
2015/04/14 Python
matplotlib绘制动画代码示例
2018/01/02 Python
pandas 数据归一化以及行删除例程的方法
2018/11/10 Python
Python3.5文件修改操作实例分析
2019/05/01 Python
python中通过selenium简单操作及元素定位知识点总结
2019/09/10 Python
Python ConfigParser模块的使用示例
2020/10/12 Python
使用html2canvas实现将html内容写入到canvas中生成图片
2020/01/03 HTML / CSS
中国专业的综合网上购物商城:京东
2016/08/02 全球购物
美国用餐电影院:Alamo Drafthouse Cinema
2020/01/23 全球购物
护理自荐信
2013/10/22 职场文书
销售代理协议书
2014/09/30 职场文书
优秀大学生事迹材料
2014/12/24 职场文书
2015年档案管理工作总结
2015/04/08 职场文书
迁徙的鸟观后感
2015/06/09 职场文书
食堂管理制度范本
2015/08/04 职场文书
志愿服务心得体会
2016/01/15 职场文书
vue3中的组件间通信
2021/03/31 Vue.js