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 相关文章推荐
JavaScript 读取元素的CSS信息的代码
Feb 07 Javascript
jquery form表单提交插件asp.net后台中文解码
Jun 12 Javascript
Javascript 静态页面实现随机显示广告的办法
Nov 17 Javascript
jquery实现可点击伸缩与展开的菜单效果代码
Aug 31 Javascript
【经验总结】编写JavaScript代码时应遵循的14条规律
Jun 20 Javascript
jQuery简单实现彩色云标签效果示例
Aug 01 Javascript
自制微信公众号一键排版工具
Sep 22 Javascript
jQuery输入框密码的显示隐藏【代码分享】
Apr 29 jQuery
JavaScript阻止表单提交方法(附代码)
Aug 15 Javascript
微信小程序实现折线图的示例代码
Jun 07 Javascript
vue实现短信验证码登录功能(流程详解)
Dec 10 Javascript
Vue SSR 即时编译技术的实现
May 06 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
星际争霸任务指南——神族
2020/03/04 星际争霸
PHP操作数组的一些函数整理介绍
2011/07/17 PHP
PHP错误处理函数
2016/04/03 PHP
jquery 弹出层注册页面等(asp.net后台)
2010/06/17 Javascript
常见JS效果之图片减速度滚动实现代码
2011/12/08 Javascript
用jquery实现动画跳到顶部和底部(这个比较简单)
2014/09/01 Javascript
js操作滚动条事件实例
2015/01/29 Javascript
对Web开发中前端框架与前端类库的一些思考
2015/03/27 Javascript
jquery中val()方法是从最后一个选项往前读取的
2015/09/06 Javascript
页面内容排序插件jSort使用方法
2015/10/10 Javascript
jquery关于事件冒泡和事件委托的技巧及阻止与允许事件冒泡的三种实现方法
2015/11/27 Javascript
json定义及jquery操作json的方法
2016/10/03 Javascript
微信小程序 教程之列表渲染
2016/10/18 Javascript
浅谈js数组和splice的用法
2016/12/04 Javascript
xmlplus组件设计系列之网格(DataGrid)(10)
2017/05/05 Javascript
微信小程序封装http访问网络库实例代码
2017/05/24 Javascript
关于vue中 $emit的用法详解
2018/04/12 Javascript
详解vuex结合localstorage动态监听storage的变化
2018/05/03 Javascript
一文了解Vue中的nextTick
2019/05/06 Javascript
python django 实现验证码的功能实例代码
2017/05/18 Python
python利用smtplib实现QQ邮箱发送邮件
2020/05/20 Python
python中从str中提取元素到list以及将list转换为str的方法
2018/06/26 Python
Python判断一个list中是否包含另一个list全部元素的方法分析
2018/12/24 Python
Python语言检测模块langid和langdetect的使用实例
2019/02/19 Python
django写用户登录判定并跳转制定页面的实例
2019/08/21 Python
迪斯尼商品官方网站:ShopDisney
2016/08/01 全球购物
瑞典在互联网上最大的宠物商店:Animail
2020/10/31 全球购物
如何减少垃圾回收让内存更加有效使用
2013/10/18 面试题
医学院校毕业生自荐信范文
2014/01/01 职场文书
企业军训感想
2014/02/07 职场文书
运动会通讯稿200字
2014/02/16 职场文书
计算机毕业生自荐信
2014/06/12 职场文书
校园运动会广播稿
2014/10/06 职场文书
3招让你摆脱即兴讲话冷场尴尬
2019/08/08 职场文书
详解MySQL数据库千万级数据查询和存储
2021/05/18 MySQL
Springboot集成kafka高级应用实战分享
2022/08/14 Java/Android