javascript中UMD规范的代码推演


Posted in Javascript onAugust 29, 2018

1. UMD规范

地址:https://github.com/umdjs/umd

UMD规范,就是所有规范里长得最丑的那个,没有之一!!!它是为了让模块同时兼容AMD和CommonJs规范而出现的,多被一些需要同时支持浏览器端和服务端引用的第三方库所使用。UMD是一个时代的产物,当各种环境最终实现ES harmony的统一的规范后,它也将退出历史舞台。

UMD规范的结构乍一看非常复杂,主要是因为想要看懂这段范式需要一些javascript基础知识,它的基本结构是这样的:

(function (root, factory) {
 if (typeof define === 'function' && define.amd) {
  // AMD
  define(['jquery', 'underscore'], factory);
 } else if (typeof exports === 'object') {
  // Node, CommonJS之类的
  module.exports = factory(require('jquery'), require('underscore'));
 } else {
  // 浏览器全局变量(root 即 window)
  root.returnExports = factory(root.jQuery, root._);
 }
}(this, function ($, _) {
 // 方法
 function a(){}; // 私有方法,因为它没被返回 (见下面)
 function b(){}; // 公共方法,因为被返回了
 function c(){}; // 公共方法,因为被返回了

 // 暴露公共方法
 return {
  b: b,
  c: c
 }
}));

2. 源码范式推演
2.1 基本结构

先来看最外层的结构:

(function (){}());

非常简单,就是一个自执行函数。既然它是一个模块化的标准,也就意味着这个自执行函数最终可以导出一个模块,那么从代码的角度来讲实际上有两种常见的实现方式:

  1. return返回一个模块;
  2. 实参传入一个对象,把函数内部生成好的需要导出的东西挂在这个对象的属性上;

可以看到上面的函数体内部是没有return语句的,那么可以猜测UMD在实现时是采用了第二种方式。既然UMD是一种模块化的规范,那么它的功能就是根据使用要求生产模块,也就是说它的职责定位叫做模块工厂,我们可以定义一个factory方法,每当执行该方法时,就回返回一个模块,所以它的基本结构就变成了如下的样子:

(function (factory){
 //假设没有使用任何模块化方案,那么将工厂函数执行后返回的内容直接挂载到全局
 window.Some_Attr = factory();
}(function(){
 //自定义模块主体的内容
 /*
  var a,b,c
  function a1(){}
  function b1(){}
  function c1(){}
  return {
   a:a1,
   b:b1
  }
  */
}))

也就是说我们自定义一个匿名函数,然后把它当做实参传给了自执行函数,然后在自执行函数内部通过形参来访问这个工厂方法(或者你会更熟悉回调函数或callback这样的叫法),把它简单地挂在到全局对象上,这样就完成了基本的模块导出。

有的时候我们也希望可以将模块挂载到非全局的环境,将挂载对象动态传入可以让代码变得更灵活,此处涉及到一个基础知识,就是浏览器环境中的全局对象拥有parent,top,self三个属性来追踪页面中嵌入<iframe>后引入的新的Window对象的,单页面Window.self是指向自己的,代码中常通过是否包含self属性来鉴别全局对象,所以此处的写法可以改进为兼容:

(function(root,factory){
 root.Some_Attr = factory();
}(self !== undefined ? self : this, function(){
 
}));

2.2 适配AMD

接着我们先来加入AMD的规范的适配,规范地址:AMD规范github地址:https://github.com/amdjs/amdjs-api/blob/master/AMD.md

/*
* AMD规范的模块定义格式是define(id?, dependencies?, factory),factory就是实际的模块内容
*/
(function (factory){
 //判断全局环境是否支持AMD标准
 if(typeof define === 'function' && define.amd){
  //定义一个AMD模块
  define([/*denpendencies*/],factory);
 }
}(function(/*formal parameters*/){
 //自定义模块主体的内容
 /*
  var a,b,c
  function a1(){}
  function b1(){}
  function c1(){}
  return {
   a:a1,
   b:b1
  }
  */
}))

2.3 适配CommonJs

接着我们先来加入CommonJs的规范的适配:

/*
* CommonJs规范使用require('moduleName')的格式来引用模块,使用module.exports对象输出模块,所以只要把模块的输出内容挂载到module.exports上就完成了模块定义。
*/
(function (factory){
 //判断全局环境是否支持CommonJs标准
  if(typeof exports === 'object' && typeof define !== 'function'){
    module.exports = factory(/*require(moduleA), require(moduleB)*/);
  }
}(function(/*formal parameters*/){
 //自定义模块主体的内容
 /*
  var a,b,c
  function a1(){}
  function b1(){}
  function c1(){}
  return {
   a:a1,
   b:b1
  }
  */
}))

加入对CommonJs的适配后,函数主体中return的内容(一般是一个对象)就被挂载到了module.exports上,如果你编写过node.js代码,对此一定不会陌生。

把上面的片段揉到一块,你也就看懂UMD的样子了。

3. 更具针对性的UMD范式

UMD在其github主页上提供了更具针对性的范式,适用于不同的场景,感兴趣的读者可以自行查看(地址在第一节已经给出)。

javascript中UMD规范的代码推演

在此贴一个可能对大多数开发者比较有用的jqueryPlugin的开发范式,如果看懂了上面的分析,那么下面的代码应该不难看懂:

// Uses CommonJS, AMD or browser globals to create a jQuery plugin.
(function (factory) {
 if (typeof define === 'function' && define.amd) {
  // AMD. Register as an anonymous module.
  define(['jquery'], factory);
 } else if (typeof module === 'object' && module.exports) {
  // Node/CommonJS
  module.exports = function( root, jQuery ) {
   if ( jQuery === undefined ) {
    // require('jQuery') returns a factory that requires window to
    // build a jQuery instance, we normalize how we use modules
    // that require this pattern but the window provided is a noop
    // if it's defined (how jquery works)
    if ( typeof window !== 'undefined' ) {
     jQuery = require('jquery');
    }
    else {
     jQuery = require('jquery')(root);
    }
   }
   factory(jQuery);
   return jQuery;
  };
 } else {
  // Browser globals
  factory(jQuery);
 }
}(function ($) {
 $.fn.jqueryPlugin = function () { return true; };
}));

4. 模块化开发

前端模块化本身是一个稍显混乱的话题,笔者自己最初也是require( )和require.js傻傻分不清楚,但模块化是前端开发中非常重要的课题,如果你不想一辈子只是在一个页面内写代码,这一关是一定要过的,感兴趣的读者可以按照下面的基本类别划分分块进行学习。

javascript中UMD规范的代码推演

Javascript 相关文章推荐
jQuery中与toggleClass等价的程序段 以及未来学习的方向
Mar 18 Javascript
jquery 按钮状态效果 正常、移上、按下
Aug 12 Javascript
在页面加载完成后通过jquery给多个span赋值
May 21 Javascript
使用JS+plupload直接批量上传图片到又拍云
Dec 01 Javascript
jquery实现拖拽调整Div大小
Jan 30 Javascript
JS中Location使用详解
May 12 Javascript
浅析Node.js中使用依赖注入的相关问题及解决方法
Jun 24 Javascript
使用jquery+CSS3实现仿windows10开始菜单的下拉导航菜单特效
Sep 24 Javascript
AngularJS 表达式详细讲解及实例代码
Jul 26 Javascript
JavaScript中日期函数的相关操作知识
Aug 03 Javascript
JS求Number类型数组中最大元素方法
Apr 08 Javascript
微信小程序开发常见问题及解决方案
Jul 11 Javascript
详解webpack自定义loader初探
Aug 29 #Javascript
在vue中使用SockJS实现webSocket通信的过程
Aug 29 #Javascript
微信小程序自定义select下拉选项框组件的实现代码
Aug 28 #Javascript
微信小程序中上传图片并进行压缩的实现代码
Aug 28 #Javascript
vee-validate vue 2.0自定义表单验证的实例
Aug 28 #Javascript
vue+element-ui动态生成多级表头的方法
Aug 28 #Javascript
jQuery实现的响应鼠标移动方向插件用法示例【附源码下载】
Aug 28 #jQuery
You might like
PHP中如何使用session实现保存用户登录信息
2015/10/20 PHP
thinkPHP+phpexcel实现excel报表输出功能示例
2017/06/06 PHP
JavaScript获取/更改文本框的值的实例代码
2013/08/02 Javascript
js单例模式详解实例
2013/11/21 Javascript
判断javascript的数据类型(示例代码)
2013/12/11 Javascript
js进行表单验证实例分析
2015/02/10 Javascript
EasyUI加载完Html内容样式渲染完成后显示
2016/07/25 Javascript
对Js OOP编程 创建对象的一些全面理解
2016/07/26 Javascript
JQuery遍历元素的父辈和祖先的方法
2016/09/18 Javascript
IntersectionObserver API 详解篇
2016/12/11 Javascript
JS使用正则表达式验证身份证号码
2017/06/23 Javascript
利用JQuery操作iframe父页面、子页面的元素和方法汇总
2017/09/10 jQuery
Three.js利用Detector.js插件如何实现兼容性检测详解
2017/09/26 Javascript
JavaScript常用数学函数用法示例
2018/05/14 Javascript
JavaScript门道之标准库
2018/05/26 Javascript
一文了解vue-router之hash模式和history模式
2019/05/31 Javascript
微信小程序如何通过用户授权获取手机号(getPhoneNumber)
2020/01/21 Javascript
基于vue和bootstrap实现简单留言板功能
2020/05/30 Javascript
Python查询IP地址归属完整代码
2017/06/21 Python
Django csrf 两种方法设置form的实例
2019/02/03 Python
Python 抓取微信公众号账号信息的方法
2019/06/14 Python
pytorch torch.expand和torch.repeat的区别详解
2019/11/05 Python
浅谈python出错时traceback的解读
2020/07/15 Python
纯css3制作网站后台管理面板
2014/12/30 HTML / CSS
世界上最全面的汽车零部件和配件集合:JC Whitney
2016/09/04 全球购物
来自圣地亚哥的实惠太阳镜:Knockaround
2018/08/27 全球购物
英国在线电子和小工具商店:TecoBuy
2018/10/06 全球购物
Notino匈牙利:购买香水和化妆品
2019/04/12 全球购物
规划编制实施方案
2014/03/15 职场文书
学生喝酒检讨书500字
2014/11/02 职场文书
2019中秋节祝福语大全,提前收藏啦
2019/09/10 职场文书
Python机器学习三大件之一numpy
2021/05/10 Python
Python djanjo之csrf防跨站攻击实验过程
2021/05/14 Python
python中的装饰器该如何使用
2021/06/18 Python
关于Vue中的options选项
2022/03/22 Vue.js
PostgreSQL事务回卷实战案例详析
2022/03/25 PostgreSQL