javascript中UMD规范的代码推演

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

在此贴一个可能对大多数开发者比较有用的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傻傻分不清楚,但模块化是前端开发中非常重要的课题,如果你不想一辈子只是在一个页面内写代码,这一关是一定要过的,感兴趣的读者可以按照下面的基本类别划分分块进行学习。

(0)

相关推荐

  • 解决vue.js在编写过程中出现空格不规范报错的问题

    找到build文件夹下面的webpack.base.conf.js文件. 然后打开该文件,找到图下这段代码,把他注释掉. 注释掉之后,再进行子页面等编写的时候,空格不规范的情况下也不会再报错啦.因为这个报错对于初学者来说实在头大.哈哈O(∩_∩)O哈哈~ 我标注的这些地方,原本是有严格的空格规范要求的,这些报错真是另人烦躁呀o(╥﹏╥)o 反正我把这个问题解决了,特别开心哒哒哒~~~ 以上这篇解决vue.js在编写过程中出现空格不规范报错的问题就是小编分享给大家的全部内容了,希望能给大家一个参考

  • 5 种JavaScript编码规范

    什么是编码规范 编码规范就是指导如何编写和组织代码的一系列标准.通过阅读这些编码规范,你可以知道在各个公司里代码是如何编写的. 我们为什么需要编码规范 一个主要的原因是:每个人写代码的方式都是不同的.我可能喜欢这么写,而你喜欢用另一种方法写.如果我们只处理自己的代码,这样并没有什么问题.但如果有成千上万的程序员同时在一个代码库上面工作呢?如果没有规范,事情很快会变得一团糟.代码规范可以让新人迅速的熟悉相关的代码,并且也能写出让其他程序员简单易懂的代码. Airbnb JavaScript Sty

  • js Element Traversal规范中的元素遍历方法

    支持Element Traversal 规范的浏览器有IE 9+.Firefox 3.5+.Safari 4+.Chrome 和Opera 10+. 对于元素间的空格,在IE9之前,都不会返回文档节点,其它的所有浏览器都会返回文档节点. 为了兼容浏览器这间的差异,又不更改已有的DOM 标准,所以有了 Element Traversal 规范. 这个规范为 元素增加了 5 个 属性 childElementCount firstElementChild lastElementChild previ

  • 超全面的JavaScript开发规范(推荐)

    这篇文章主要介绍的是关于JS的命名规范.注释规范以及框架开发的一些问题,首先来看看目录. 目录 1. 命名规范:介绍变量.函数.常量.构造函数.类的成员等等的命名规范 2. 注释规范:介绍单行注释.多行注释以及函数注释 3. 框架开发:介绍全局变量冲突.单全局变量以及命名空间 一.命名规范 驼峰式命名法介绍: 驼峰式命名法由小(大)写字母开始,后续每个单词首字母都大写. 按照第一个字母是否大写,分为: ① Pascal Case 大驼峰式命名法:首字母大写.eg:StudentInfo.User

  • 最全的Javascript编码规范(推荐)

    1.嵌入规则 Javascript程序应该尽量放在.js的文件中,需要调用的时候在页面中以<script src="filename.js">的形式包含进来.Javascript代码若不是该页面专用的,则应尽量避免在页面中直接编写Javascript代码. 2.对齐缩进与换行 a) 缩进 在同一系统中应采用同一种缩进标准,本文提倡缩进大小为4个空格.各编译器对Tab键所代替的空白大小定义不同.建议在设置开发环境时,将编辑器里的Tab快捷键重新设置成4个空格.多数编译器提供了

  • JavaScript常用代码书写规范的超全面总结

    一.全局命名空间污染 总是将代码包裹在一个立即的函数表达式里面,形成一个独立的模块. 不推荐 var x = 10, y = 100; console.log(window.x + ' ' + window.y); 推荐 ;(function(window){ 'use strict'; var x = 10, y = 100; console.log(window.x + ' ' + window.y); }(window)); 二.立即执行函数 在立即执行函数里面,如果有用到全局变量应该通过

  • 详谈js模块化规范

    1. CommonJS 用于服务端模块化编程,比如nodejs就采用此规范: 一个文件就是一个模块,require方法用来加载模块,该方法读取一个文件并执行,最后返回文件内部的module.exports对象: require是默认读取.js文件的,所以require(模块名)可以不写后缀: 同步加载,由于服务端加载的模块一般在本地,所以可以这样:但是在客户器端如果一个模块过大就会导致页面"假死": module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上

  • 老生常谈javascript变量的命名规范和注释

    简单说,标识符命名规则如下: 第一个字符可以是任意Unicode字母,以及美元符号($)和下划线(_). 第二个字符及后面的字符,还可以用数字. 下面这些都是合法的标识符. arg0 _tmp $elem π 下面这些则是不合法的标识符. 1a 23 *** a+b -d 中文是合法的标识符,可以用作变量名. var 临时变量 = 1; JavaScript有一些保留字,不能用作标识符:arguments.break.case.catch.class.const.continue.debugge

  • Javascript 编码约定(编码规范)

    1.使用 strict 模式 在一个作用域(包括函数作用域.全局作用域)中,可以使用 "use strict"; 来开启 strict 模式. 2.缩进 用 Tab 键进行代码缩进,以节约代码大小,使用4个空格的宽度来进行缩进(JSLint 建议). 3.符号 1) 大括号 与语句放同一行,放于最后面:仅有一行语句,也使用大括号: if (true) { //true } else { //false } while (true) { //alert(1); } 2) 空格 在逗号.分

  • javascript中UMD规范的代码推演

    1. UMD规范 地址:https://github.com/umdjs/umd UMD规范,就是所有规范里长得最丑的那个,没有之一!!!它是为了让模块同时兼容AMD和CommonJs规范而出现的,多被一些需要同时支持浏览器端和服务端引用的第三方库所使用.UMD是一个时代的产物,当各种环境最终实现ES harmony的统一的规范后,它也将退出历史舞台. UMD规范的结构乍一看非常复杂,主要是因为想要看懂这段范式需要一些javascript基础知识,它的基本结构是这样的: (function (r

  • JavaScript中ES6规范中let和const的用法和区别

    ES6-- let 和 const 命令 引言 本文主要讲解ES6中变量的相关操作,变量的命名, 讲解 var. let . const 三者的区别 正文 ES6中的 let 和 const 都是用来声明变量的, 他们与 var 有所区别 let 命令 我们都知道在for循环中,我们命名的变量 i 一般都只是为了在这个循环中使用,才临时命名的, 我们希望循环结束后,这个变量就消失, 但是却相反,用 var 命名的变量,在 for 循环结束后并不会销毁,而会存在于全局中. for(var i=0;

  • 深入理解JavaScript中的语法和代码结构

    概述 所有编程语言都必须遵守特定的规则才能运行. 确定编程语言的正确结构的这组规则称为语法. 许多编程语言主要由具有语法变化的类似概念组成. 在本教程中,我们将介绍JavaScript语法和代码结构的许多规则和约定. 功能性和可读性 在开始使用JavaScript时,功能性和可读性是关注语法的两个重要原因. 有些语法规则是JavaScript功能所必需的.如果不遵循它们,控制台将抛出一个错误,脚本将停止执行. 考虑"Hello,World!"中的语法错误.程序: // Example

  • 如何在JavaScript中运行.NET Core代码详情

    目录 一.前言 二.DotNetJS 三.Demo 1. 创建项目 2. 实现C#代码 3. 实现JS代码 4. 运行效果 四.结论 一.前言 在.NET Core中运行JavaScript代码,目前已经有很多实现方案. 但是,如果你希望在纯JavaScript环境中运行.NET Core代码呢? 那么,DotNetJS可能对你有所帮助. 二.DotNetJS DotNetJS可以将C#项目编译为与任何环境兼容的单文件JavaScript库,无论是Web浏览器,Node.js还是自定义限制空间,

  • 在JavaScript中构建ArrayList示例代码

    前面我们介绍了JavaScript Array 的API,在JavaScript 中 数组 本身就非常强大,可以存储任意类型,且长度自动扩容,又提供 遍历, 过滤,等多个操作数组的方法. 简直完爆Java的的数组(长度固定,单一类型).而Java中的集合类 就是弥补数组不足,其底层大多使用Object [] 存储,只是提供动态扩容的策略,当然JDK的 API 之丰富,是其他语言难以匹敌的. 但是不妨碍我对Java.JavaScript的喜爱. Java就像 一个中年老妇女,你总能在JDK中 看到

  • javascript中直接写php代码的方法

    一.在javascript中嵌入php代码javascript若是通过js文件包含进来的,那么js文件中也可以直接写php代码,只不过包含js文件是扩展名要改成php,如: 复制代码 代码如下: <script herf="js/demo.js.php"></script> 二.javascript函数参数的默认值c语言中可以通过这样来设置默认参数: 复制代码 代码如下: void foo(int a, int b = 1, bool c = false); 但

  • JavaScript中URL编码函数代码

    以下是对变量值的URL编码总结 : 建议用encodeURIComponent() , GET 和POST方式都可以发送过去 . JavaScript中存在几种对URL字符串进行编码的方法:escape(),encodeURI(),以及encodeURIComponent().这几种编码所起的作用各不相同. escape() 方法: 采用ISO Latin字符集对指定的字符串进行编码.所有的空格符.标点符号.特殊字符以及其他非ASCII字符都将被转化成%xx格式的字符编码(xx等于该字符在字符集

  • JavaScript中的排序算法代码

    作为排序依据的数据项称为"排序码",也即数据元素的关键码.为了便于查找,通常希望计算机中的数据表是按关键码有序的.如有序表的折半查找,查找效率较高.还有,二叉排序树.B-树和B+树的构造过程就是一个排序过程.若关键码是主关键码,则对于任意待排序序列,经排序后得到的结果是唯一的:若关键码是次关键码,排序结果可能不唯一,这是因为具有相同关键码的数据元素,这些元素在排序结果中,它们之间的的位置关系与排序前不能保持. 若对任意的数据元素序列,使用某个排序方法,对它按关键码进行排序:若相同关键码

  • 在javascript中执行任意html代码的方法示例解读

    今天码代码中偶然发现有一种情况javascript的eval()函数无法执行html代码,比如: 复制代码 代码如下: <script>eval('<li>hehe</li>')</script> 代码是不会执行的,但是改为如下就可以执行了: 复制代码 代码如下: <script>eval('</script><li>hehe</li><script>')</script>

  • Vue项目中ESlint规范示例代码

    前言 eslint是一种代码风格管理的工具,可以制定一些代码编写规范,在vue项目中经常用到,本文就给大家分享了开发项目中使用的eslint校验规范,供参考: 示例代码 module.exports = { root: true, parserOptions: { parser: 'babel-eslint', sourceType: 'module' }, env: { browser: true, node: true, es6: true, }, extends: ['plugin:vue

随机推荐