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 相关文章推荐
JavaScript开发时的五个注意事项
Dec 08 Javascript
Checbox的操作含已选、未选及判断代码
Nov 07 Javascript
javascript 操作符(~、&amp;、|、^、)使用案例
Dec 31 Javascript
JS操作HTML自定义属性的方法
Feb 10 Javascript
使用Meteor配合Node.js编写实时聊天应用的范例
Jun 23 Javascript
基于javascript实现随机颜色变化效果
Jan 14 Javascript
点击页面任何位置隐藏div的实现方法
Sep 05 Javascript
JS判断输入的字符串是否是数字的方法(正则表达式)
Nov 29 Javascript
json数据格式常见操作示例
Jun 13 Javascript
js实现简单掷骰子小游戏
Oct 24 Javascript
axios如何取消重复无用的请求详解
Dec 15 Javascript
element 动态合并表格的步骤
Dec 31 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合并两个数组的两种方式的异同
2012/09/14 PHP
javascript[js]获取url参数的代码
2007/10/17 Javascript
JAVASCRIPT实现的WEB页面跳转以及页面间传值方法
2010/05/13 Javascript
Node.js node-schedule定时任务隔多少分钟执行一次的方法
2015/02/10 Javascript
在浏览器中打开或关闭JavaScript的方法
2015/06/03 Javascript
AngularJS页面访问时出现页面闪烁问题的解决
2016/03/06 Javascript
AngularJS  双向数据绑定详解简单实例
2016/10/20 Javascript
webpack下实现动态引入文件方法
2018/02/22 Javascript
Vue.js实现可配置的登录表单代码详解
2018/03/29 Javascript
vue2.0实现移动端的输入框实时检索更新列表功能
2018/05/08 Javascript
layer弹出层 iframe层去掉滚动条的实例代码
2018/08/17 Javascript
PWA介绍及快速上手搭建一个PWA应用的方法
2019/01/27 Javascript
小程序自定义单页面、全局导航栏的实现代码
2019/03/15 Javascript
vue输入节流,避免实时请求接口的实例代码
2019/10/30 Javascript
VueCli4项目配置反向代理proxy的方法步骤
2020/05/17 Javascript
vue实现lodop打印功能的示例
2020/11/11 Javascript
[00:12]DAC SOLO赛卫冕冠军 VG.Paparazi灬展现SOLO技巧
2018/04/06 DOTA
[54:27]TNC vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python读取Android permission文件
2013/11/01 Python
Python操作CouchDB数据库简单示例
2015/03/10 Python
Python EOL while scanning string literal问题解决方法
2020/09/18 Python
Python多线程结合队列下载百度音乐的方法
2015/07/27 Python
Python字符串的一些操作方法总结
2019/06/10 Python
pyQT5 实现窗体之间传值的示例
2019/06/20 Python
如何在python开发工具PyCharm中搭建QtPy环境(教程详解)
2020/02/04 Python
Python MySQLdb 执行sql语句时的参数传递方式
2020/03/04 Python
Html5剪切板功能的实现代码
2018/06/29 HTML / CSS
迪卡侬英国官网:Decathlon英国
2017/04/08 全球购物
德国滑雪和户外用品网上商店:XSPO
2019/10/30 全球购物
幼儿园小班评语
2014/04/18 职场文书
三方协议书范本
2014/04/22 职场文书
推荐信怎么写
2014/05/09 职场文书
官僚主义现象查摆问题整改措施
2014/10/04 职场文书
工作收入住址证明
2014/10/28 职场文书
党支部承诺书
2015/01/20 职场文书
博物馆观后感
2015/06/05 职场文书