zoukankan      html  css  js  c++  java
  • 深入理解模块化编程

    1.模块化开发规范

    JavaScript中所有对象的属性都是公共的,并没有什么明确的方法来表明属性能否从对象的外部被访问,而有时候我们并不希望对象的属性被外界访问。一种方式方式通过命名约定的形式,比如在变量的前面加下划线(_)。还有一些其他的方式是属性完全私有化。

    2.为什么要模块化

    在模块化没有出现之前,我们JavaScript脚本大概是这样的:

    <script src="module1.js"></script>
        <script src="module2.js"></script>
        <script src="module3.js"></script>
        <script src="module4.js"></script>
        ....

    但我们引入多个js文件时,会存在一些问题:

    • 把所有的代码放到全局环境会引起冲突
    • 各个脚本必须按照严格的依赖顺序放置
    • 在大型的项目中,可能会引入很多的js脚本,script就会变得很多,并且难以维护。

    为了解决这些问题,涌现了各种模块化的方案。

    3.模块化的方式

    这种方式是创建对象的一种方法,用于创建具有私有属性的对象。基本思路是使用一个立即执行的函数表达式,返回一个对象。该函数表达式可以包含任意数量的局部变量,这些变量从函数的外部是无法访问到的。因为返回的对象是在自执行函数内部声明的,所以对象中定义的方法可以访问自执行函数内的局部变量,这些方法被具有特权的方法。

     var p2 = (function(){
    
                var money = 30000;
    
                return {
                    name: 'lisi',
                    sayMoney: function(){
                        return money;
                    }
                };
    
            }());

    4. CommonJS

    我们在前端的js代码在没有模块化之前也能正常执行,但是在服务器端的js脚本必须要被模块化才能正常工作。所以虽然JavaScript在前端发展了这么多年,第一个流行的模块化规范却是由服务器端的js应用发展起来的。CommonJS规范是由NodeJS发扬光大的。

    1. 定义模块

    在CommonJS规范中,一个单独的JS文件就是一个模块。每个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。

    1. 模块输出

    模块只有一个出口,module.exports对象,我们需要把需要输出的内容放入该模块

    1. 加载模块

    加载模块使用require()方法,该方法读取一个文件并执行,返回文件内部的module.exprots对象

    例如,我们写了这样一个文件myModule1.js

    var name = '无忌';
    function sayName(){
        console.log(name);
    };
    
    function sayFullName(firstName){
        console.log(firstName + name);
    };
    module.exports = {
        printName:sayName,
        printFullName:sayFullName
    };

    我们的模块定义好了,那我们怎样使用这个模块呢?例如,我们创建了myModule2.js文件:

    var module1 = require('./myModule1.js');
    
    module1.printName();
    module1.printFullName('张');

    在node环境下,require方法在引入其他模块的时候是同步的,可以轻松的控制模块的引入顺序,保证了模块之间的依赖顺序。但是在浏览器中却不是这样的,因为我们的<script>标签天生异步,在加载js文件的时候是异步的,也就意味着不能保证模块之间的正确依赖。

    5. AMD规范

    AMD即Asynchronous Module Definition,异步模块定义。它是在浏览器端实现模块化开发的规范。由于该规范不是JavaScript原始支持的,使用AMD规范进行开发的时候需要引入第三方的库函数,也就是鼎鼎大名的RequireJS

    RequireJS主要解决两个问题:

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

    3. 定义模块

    RequireJS定义了一个define函数,用来定模块。

    define(id, [dependencies], factory);

    • id:可选参数,用来定义模块的标识,如果没有提供参数的话,默认为文件的名字。
    • dependencies:当前模块依赖的其他模块,数组。
    • factory:工厂方法,初始化模块需要执行的函数或对象。如果为函数,它只被执行一次。如果是对象,此对象会作为模块的输出值。
    // amdModule1.js
    
    define('amdModule1',[],function(){
        
        console.log('模块一');
        
        var name= '张三';
        
        var money = 1000;
        
        var sayName = function(){
            return name;
        }
        var sayMoney = function(){
            return money;
        }
        return {
            sayName:sayName,
            sayMoney:sayMoney
        }
    })
    
    // module2.js
    
    
    define('amdModule2',['amdModule1'],function(amdModule1){
        
        console.log('模块二');
        
        var name = '李四';
        
        var weight = 80;
        
        var sayName = function(){
            return amdModule1.sayName();
        }
        var sayWeight = function(){
            return weight;
        }
        return {
            sayWeight:sayWeight,
            name:name,
            sayName:sayName
        };
    })
    1. 在页面中加载模块

    加载模块需要使用require()函数。

    require([dependencies], function(){});

    • dependencies:该参数是一个数组,表示所依赖的模块。
    • function:这是一个回调函数,当所依赖的模块都加载成功之后,将调用该回调方法。依赖的模块会以参数的形式传入该函数,从而在回调函数内部就可以使用这些模块。
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <script src="require.js"></script>
            <script type="text/javascript" src="amdModule1.js"></script>
            <script type="text/javascript" src="amdModule2.js"></script>
            <script type="text/javascript">
                require(['amdModule1','amdModule2'],function(amdModule1,amdModule2){
                    console.log(amdModule1.sayName());  //张三
                    console.log(amdModule1.name); //undefined
                    console.log(amdModule2.sayName()); //张三
                    console.log(amdModule2.sayWeight()); //80
                });
            </script>
        </body>
    </html>

    require()函数在加载依赖的模块时,是异步加载的,这样浏览器就不会失去响应,回调函数只有在所依赖的全部模块都被被成功加载之后才执行,因此,解决了依赖性的问题。

    6. CMD规范

    CMD即Common Module Definition通用模块定义。它解决的问题和AMD规范是一样的,只不过在模块定义方式和模块加载时机上不同。CMD也需要额外的引入第三方的库文件,SeaJS。

    SeaJS推崇一个模块一个文件,遵循统一的写法:

    define(id, dependencies, factory);

    因为CMD推崇一个文件一个模块,所以经常使用文件名作为模块的ID;CMD推崇就近原则,所以一般不再define的参数中写依赖,在factory函数中写。

    • require:我们定义的模块可能会依赖其他模块,这个时候就可使用require()引入依赖。
    • exports:等价于module.exports,只是为了方便我们使用
    • module.exports:用于存放模块需要暴露的属性
    1. 定义模块
    // cmdModule1.js
    
    define(function(require,exports,module){
        var name = '张三';
        function sayName(){
            return name;
        }
        module.exports={
            sayName:sayName
        }
    })
    
    // cmdModule2.js
    
    
    define(function(require,exports,module){
        
        var cmdModule1 = require('cmdModule1.js');
        console.log('模块');
        function sayName(){
            return cmdModule1.sayName();
        }
        module.exports={
            sayName:sayName
        }
    })
    1. 使用模块
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <script src="sea.js"></script>
            <script src="cmdModule2.js"></script>
            <script src="cmdModule1.js"></script>
            <script type="text/javascript">
                seajs.use(['cmdModule2.js','cmdModule1.js'],function(cmdModule2,cmdModule1){
                    console.log(cmdModule2.sayName());
                    console.log(cmdModule1.sayName());
                })
            </script>
        </body>
    </html>

    7. AMD和CMD规范的区别

    AMD在加载模块完成后会立即执行该模块,所有的模块都加载完成后执行require方法中的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网速,谁先下载下来,谁先执行,但是我们的主逻辑一定是在所有的依赖模块都被加载完成后才执行。

    CMD加载完某个模块的时候并不执行,只是把它们下载下来而已,在所有的模块下载完成后,当使用require请求某个模块的时候,才执行对应的模块。

  • 相关阅读:
    运维安全、架构、日志管理等要安装的东西,一直在更新,欢迎大家评论
    http协议的发展史
    uni-app实现通话录音实时上传、后端php-安卓手机
    uni-app H5 plus.io 获取手机指定路径目录下所有文件
    Laravel框架部署过程中的步骤:安装 composer、切换镜像、安装laravel、创建项目
    vue 强制修改el-input样式
    ide激活码,可激活goland、phpstorm、webstorm、Pycharm
    PHP转Go函数库
    Uni-app父组件如何调用子组件的方法 | 父页面如何调用子页面的方法
    Uni-app子组件如何调用父组件的方法 | 子页面如何调用父页面的方法
  • 原文地址:https://www.cnblogs.com/zhoulifeng/p/7545387.html
Copyright © 2011-2022 走看看