zoukankan      html  css  js  c++  java
  • javascript基础修炼(4)——UMD规范的代码推演

    javascript基础修炼(4)——UMD规范的代码推演

    1. UMD规范

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

    UMD规范,就是所有规范里长得最丑的那个,没有之一!!!它是为了让模块同时兼容AMDCommonJs规范而出现的,多被一些需要同时支持浏览器端和服务端引用的第三方库所使用。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地址

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

  • 相关阅读:
    s s r 多用户 简单配置
    iptables vsftp timeout
    透明控件的通用解决方案
    一个带有可选自定义框架的透明对话框类
    把你的框架窗口一个影子
    WinForms形成皮肤
    WPF加载启动画面
    酷,半透明和形状对话框与标准的控制Windows 2000及以上
    在MFC应用程序中创建web风格的GUI
    画在WinForms控制
  • 原文地址:https://www.cnblogs.com/dashnowords/p/9537315.html
Copyright © 2011-2022 走看看