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 相关文章推荐
IE和Mozilla的兼容性汇总event
Aug 12 Javascript
用JS判断IE版本的代码 超管用!
Aug 09 Javascript
javascript中数组中求最大值示例代码
Dec 18 Javascript
jquery中append()与appendto()用法分析
Nov 14 Javascript
简介JavaScript中getUTCMonth()方法的使用
Jun 10 Javascript
JS实现页面跳转参数不丢失的方法
Nov 28 Javascript
JS调用Android、Ios原生控件
Jan 06 Javascript
JS实现的随机排序功能算法示例
Jun 09 Javascript
elementui的默认样式修改方法
Feb 23 Javascript
记一次vue-webpack项目优化实践详解
Feb 17 Javascript
Js跳出两级循环方法代码实例
Sep 22 Javascript
vue-cli3.x配置全局的scss的时候报错问题及解决
Apr 30 Vue.js
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读取javascript设置的cookies的代码
2010/04/12 PHP
使用php发送有附件的电子邮件-(PHPMailer使用的实例分析)
2013/04/26 PHP
PHP register_shutdown_function函数的深入解析
2013/06/03 PHP
PHP导航下拉菜单的实现如此简单
2013/09/22 PHP
Opcache导致php-fpm崩溃nginx返回502
2015/03/02 PHP
PHP count()函数讲解
2019/02/03 PHP
laravel框架路由分组,中间件,命名空间,子域名,路由前缀实例分析
2020/02/18 PHP
JS代码格式化和语法着色V2
2006/10/14 Javascript
用js实现手把手教你月入万刀(转贴)
2007/11/07 Javascript
JSQL  一个 web DB 的封装
2010/05/05 Javascript
jquery动画2.元素坐标动画效果(创建一个图片走廊)
2012/08/24 Javascript
九种js弹出对话框的方法总结
2013/03/12 Javascript
JavaScript如何调试有哪些建议和技巧附五款有用的调试工具
2015/10/28 Javascript
json传值以及ajax接收详解
2016/05/24 Javascript
jQuery 全选 全部选 反选 实现代码
2016/08/17 Javascript
详解bootstrap的modal-remote两种加载方式【强化】
2017/01/27 Javascript
Vue 2.0在IE11中打开项目页面空白的问题解决
2017/07/16 Javascript
浅谈vue引入css,less遇到的坑和解决方法
2018/01/20 Javascript
如何更好的编写js async函数
2018/05/13 Javascript
AngularJS标签页tab选项卡切换功能经典实例详解
2018/05/16 Javascript
JS中实现隐藏部分姓名或者电话号码的代码
2018/07/17 Javascript
微信小程序实现的3d轮播图效果示例【基于swiper组件】
2018/12/11 Javascript
Django原生sql也能使用Paginator分页的示例代码
2017/11/15 Python
对Python3中bytes和HexStr之间的转换详解
2018/12/04 Python
python选取特定列 pandas iloc,loc,icol的使用详解(列切片及行切片)
2019/08/06 Python
Numpy 中的矩阵求逆实例
2019/08/26 Python
迪梵英国官方网站:Darphin英国
2017/12/06 全球购物
联想韩国官网:Lenovo Korea
2018/05/10 全球购物
节能宣传周活动总结
2014/05/08 职场文书
珠宝的促销活动方案
2014/08/31 职场文书
机关中层领导干部群众路线教育实践活动个人对照检查材料
2014/09/24 职场文书
三严三实心得体会范文
2014/10/13 职场文书
答谢酒会主持词
2015/07/02 职场文书
中学校园广播稿
2015/08/18 职场文书
《风不能把阳光打败》读后感3篇
2020/01/06 职场文书
联想win10摄像头打不开怎么办?win10笔记本摄像头打不开解决办法
2022/04/08 数码科技