zoukankan      html  css  js  c++  java
  • 前端模块化

    前端模块化

    函数封装

    函数一个功能就是实现特定逻辑的一组语句打包,而且JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块

    示例一:

    function fn1(){
        ...
    }
    function fn2(){
        ...
    }
    

      

    // 缺点:污染全局变量,可能发生变量名冲突,模块成员之间没联系。

    对象

    为了解决上面问题,对象的写法应运而生,可以把所有的模块成员封装在一个对象中

    示例二:

    var myModule = {
        var1: 1,
        var2: 2,
        fn1: function(){
            ...
        },
        fn2: function(){
            ...
        }
    }
    

      

    // 调用:
    myModule.fn2();
    // 缺陷:外部可以随意修改内部成员,会产生意外的安全问题
    myModule.var1 = 100;

    立即执行函数

    示例三:

    var myModule = (function(){
        var var1 = 1;
        var var2 = 2;
        function fn1(){
            ...
        }
        function fn2(){
            ...
        }
        return {
            fn1: fn1,
            fn2: fn2
        }
    })();
    

      

    放大模式和宽放大模式

    放大模式
    如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。
    示例四:

    var myModule = (function(mod){
        mod.fn3 = function(){
            ...
        };
        return mod;
    })(module1);
    

      

    上面的代码为module1模块添加了一个新方法m3(),然后返回新的module1模块。

    宽放大模式
    在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
    示例五:


    var myModule = (function(mod){
        ...
        return mod;
    })(window.module1 || {});
    

      

    与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象。

    示例六

    var myModule = (function($,Angular){
        ...
    })(jQuery,Angular);
    

      

    模块的规范
    先想一想,为什么模块很重要?
    因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
    但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套!考虑到Javascript模块现在还没有官方规范,这一点就更重要了。
    目前,通行的Javascript模块规范共有两种:CommonJS 和 AMD。

    CommonJs

    1. 定义模块
      根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global(全局)对象的属性
    2. 模块输出
      模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象
    3. 加载模块
      加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象

    示例:

    // 模块定义 myModel.js
    var name = 'xxx';
    function printName(){
        console.log(name);
    }
    function printFullName(firstName){
        console.log(firstName + name);
    }
    module.exports = {
        printName: printName,
        printFullName: printFullName
    }
    
    // 加载模块
    var nameModule = require('./myModel.js');
    nameModule.printName();
    

      

    不同的实现对require时的路径有不同要求,一般情况可以省略js拓展名,可以使用相对路径,也可以使用绝对路径,甚至可以省略路径直接使用模块名(前提是该模块是系统内置模块)

    AMD

    AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范

    由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出

    requireJS主要解决两个问题:

    1. 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
    2. js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长

    一个使用requireJS的例子

    // 定义模块 myModule.js
    define(['dependency'],function(){
        var name = 'xxx';
        function printName(){
            console.log(name);
        }
        return {
            printName: printName
        };
    });
    
    // 加载模块
    require(['myModule'],function(my){
        my.printName();
    });
    

      

    语法:
    requireJS定义了一个函数define,它是全局变量,用来定义模块
    define(id,dependencies,factory);
    // id: 可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉扩展名)
    // dependencies: 是一个当前模块依赖的模块名称数组
    // factory: 工厂方法,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值

    在页面上使用require函数加载模块
    require([dependencies],function(){ ... })
    // 第一个参数是一个数组,表示所依赖的模块
    // 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块

    require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

    CMD

    CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同

    语法:
    Sea.js 推崇一个模块一个文件,遵循统一的写法
    define(id,deps,factory)
    因为CMD推崇 1. 一个文件一个模块,所以经常就用文件名作为模块id
    2. CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写

    factory有三个参数
    function(require,exports,module)
    // require 是 factory 函数的第一个参数
    // require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口
    require(id)

    // exports 是一个对象,用来向外提供模块接口

    // module 是一个对象,上面存储了与当前模块相关联的一些属性和方法

    一个示例:
    // 定义模块 myModule.js


    define(function(require,exports,module){
       var $ = require('jquery.js');
       $('div').addClass('active'); 
    });
    

      

    // 加载模块
     
    seajs.use(['myModule.js'],function(my){
        ...
    });
    

      

    AMD与CMD区别

    1. AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
    2. CMD推崇就近依赖,只有在用到某个模块的时候再去require
      这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法

    AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同

    很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略

    同样都是异步加载模块,AMD在加载模块完成后就会执行该模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行

    CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的

    这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因



    作者:呆毛和二货
    链接:https://www.jianshu.com/p/a2394f00cbe4
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     
     
     
     
     
     
     
     
     
     
    1、路在何方? 路在脚下 2、何去何从? 每个人都在探索,未来的方向在何处。如果说某些方向是世人已经公认的,那么就先按照公认的去走吧(ps:站在巨人的肩膀上看世界会清晰)。 如果说方向,当今世人还不清晰准确。那么就大胆往前走吧,对与错并不重要。心中的方向更加重要。
  • 相关阅读:
    Maven 集成Tomcat插件
    dubbo 序列化 问题 属性值 丢失 ArrayList 解决
    docker 中安装 FastDFS 总结
    docker 从容器中拷文件到宿主机器中
    db2 相关命令
    Webphere WAS 启动
    CKEDITOR 4.6.X 版本 插件 弹出对话框 Dialog中 表格 Table 自定义样式Style 问题
    SpringMVC JSONP JSON支持
    CKEDITOR 3.4.2中 按钮事件中 动态改变图标和title 获取按钮
    git回退到远程某个版本
  • 原文地址:https://www.cnblogs.com/yuanjili666/p/13633656.html
Copyright © 2011-2022 走看看