JavaScript模块化开发 IIFE, AMD, CMD

79 阅读6分钟

模块化开发

将项目中内容/ 功能 相同的部分 开发成一个独立的文件(模块), 哪个页面需要这个内容 / 功能 就导入 这个独立的文件, 加载使用其中定义的程序

模块化开发 和 script标签导入外部文件区别

 外部文件导入 
    外部文件导入的顺序 不清晰
        外部文件的导入数据 谁先谁后 能不能改变顺序 不清楚

 外部文件导入的依懒性 不清晰
        使用了那个文件中的那个函数 不清楚

 没有防止全局变量污染

前端模块化开发的基本介绍

  1. 没有模块化的时代

    外部文件导入

  2. 模块化的洪荒时代 IIFE

    使用 立即执行函数 解决 全局变量污染问题

  3. 模块化的标准化时代 AMD CMD

    通过导入外部文件 执行设定好的模块化开发模式

  4. 模块化的当前使用方式

    ES6模块化开方式配合框架语法

IIFE(Immediately Invoked Function Expression) 立即调用函数

使用立即执行函数 防止全局变量污染 , 将全局变量定义在函数中 变成局部变量
向 window 新增属性属性值 存储数据 就可以通过window调用设定的数据

文件1a.js

// 这是一个 独立模块 
// 自己定义程序自己执行 不需要其他模块中的数据

(function(){
    // 将全局变量定义在 立即执行函数中
    let name = '张三' ;
    let age = 18 ;
    let sex = '男';

    const arr = [100,200,300,400];
    const obj = { addr:'北京' , phone:123456 , email:'123@qq.com' };

    // 将 之前的全局变量数据 使用一个对象 都定义在 window中

    window.modeA = { name , age , sex , arr , obj };
})()

文件2b.js

// 模块B是一个依赖模块 
// 在模块B中需要模块A的数据
// 通过立即执行函数的传参语法 向立即执行函数传参模块A的数据
(function( val ){

    // console.log( val );

    let name = '李四';

    let age = val.age + 2 ; 

    let sex = '女' ;

    const arr = val.arr.map( item => {
        return item * 2 ;
    })

    const obj = val.obj ;

    window.modeB = { name , age , sex , arr , obj };

})( window.modeA );

demo.html

       /*
            IIFE
                Immediately Invoked Function Expression
                    立即调用函数表达式

                使用立即执行函数 防止全局变量污染
                    将全局变量 定义在函数中 变成局部变量
                    
                向 window 新增属性属性值 存储数据
                    就可以通过window调用设定的数据
        
        */

        // window是JavaScript定义的一个对象 
        console.log( window );

        // 给window对象新增属性
        window.name = '张三' ;
        window.age = 18 ;

        // 调用模块A 定义在 window中 对象的数据
        console.log( window.modeA.name );

AMD(Asynchronous Module Definition)

概念

AMD是js社区 开发一种 前端模块化解决方案,需要导入一个require.js的文件

特点

前置依赖
一次性导入所有模块化文件,上一个导入的模块没有执行完毕 下一个导入的模块不会触发执行

页面首次打开时 会比较卡顿,之后页面的浏览执行 就不会卡顿了,一般用于大型页面的设定

基本语法

            独立模块
                define( function(){
                    定义数据和程序

                    return { 当前模块导出的数据和函数 };
                })

            依赖模块
                define( ['导入模块1' , '导入模块2' ...] , function( 参数1 , 参数2 ... ){
                    参数1   存储 导入模块1 的数据 
                    参数2   存储 导入模块2 的数据
                    ....

                    return { 当前模块导出的数据和函数 };

                })


            整合模块
                require( ['导入模块1' , '导入模块2' ...] , function( 参数1 , 参数2 ... ){
                    参数1   存储 导入模块1 的数据 
                    参数2   存储 导入模块2 的数据
                    ....

                    调用 导入的模块数据和函数

                })

        
            html文件 
                只需要导入 最终的 整合模块文件就可以
                

html文件

    <!-- 导入 AMD 外部文件 -->
    <script src="./require.js"></script>

    <!-- 只需要导入整合模块 -->
    <script src="./c.js"></script>

独立模块

// 独立模块

// 通过 define(函数(){}) 设定 模块A
// 在 函数中 使用 return的语法形式 导出模块A的数据
define(function(){
    // 定义的数据
    let name = '张三' ;
    let age = 18 ; 
    let sex = '男' ;

    const arr = [100,200,300,400];
    const obj = { addr:'北京' , phone : 123456 , email:'123@qq.com' };

    function fa1(){};
    function fa2(){};
    function fa3(){};

    // 导出数据 
    // return的数据 通过 define函数 
    // 将 return 的数据 作为 模块A 导出的数据
    return { name , age , sex , arr , obj , fa1 , fa2 , fa3 };

});


依赖模块

// 依赖模块 

// 需要依赖模块A中的数据
// 依赖模块 define( 参数1 , 参数2 )
// 参数1 是 以数组的形式 设定要导入的模块
// 参数2 是 模块B的设定 函数的参数是 对应的导入的模块的数据
define( ['./a.js'] , function( valA ){
    // console.log( valA );

    let name = '李四' ;
    let age = valA.age - 5 ;
    let sex = '女' ;

    const arr = valA.arr.map( item => {

        return item / 4 ;

    })

    const obj = valA.obj ;

    function fb1 (){}
    function fb2 (){}
    function fb3 (){}
    function fb4 (){}

    return { name , age , sex , arr , obj , fb1 , fb2 , fb3 , fb4 };
    
}) 

整合模块

// 整合模块
// 将 所有需要执行的模块 都导入这一个文件中
// html文件只要导入这个整合模块就行了

// 独立模块 依赖模块 都不能直接独立的代入html文件
// 一定是通过 整合模块 整合 独立模块 依赖模块 
// 导入的是 整合模块

require( ['./a.js' ,'./b.js' ] , function( valA , valB ){

    // 模块A 模块B 的数据 
    console.log( valA ); 
    console.log( valB ); 
})

CMD(Common Module Definition)

是 淘宝公司 玉伯团队开发的前端模块化解决方案 参考了后端 commonJS 模块化开发方式,需要导入 sea.js 外部文件

特点

即时依赖
需要哪个模块执行 导入哪个模块

首次打开页面 会比较流畅 之后页面的浏览执行 会出现卡顿问题

一般用于时效性强的页面 抢购 秒杀

基本语法

    独立模块
        define(function( 参数1, 参数2 , 参数3 ){

            设定 数据 和 函数方法 

            参数3.exports = { 导出的数据 };

        })


    依赖模块

        define(function( 参数1, 参数2 , 参数3 ){

            const 变量1 = 参数1('导入模块文件的路径');
            const 变量2 = 参数1('导入模块文件的路径');
            const 变量3 = 参数1('导入模块文件的路径');
            ....

            设定 数据 和 函数方法 

            参数3.exports = { 导出的数据 };

        })


    整合模块

        seajs.use( ['导入模块文件路径' , '导入模块文件路径' , '导入模块文件路径' ..] , function( 参数1 , 参数2 ... ){
            
            参数1, 参数2 存储 对应的外部文件导出的数据


        })
        

html文件

    <!-- 导入外部 sea.js 文件 -->
    <script src="./sea.js"></script>

    <!-- 导入整合模块文件 -->
    <script src="./c.js"></script>

独立模块

// 独立模块
define(function( require , exports , module ){

    // 定义数据和函数方法等
    let name = '张三' ;
    let age = 18 ; 
    let sex = '男' ;

    const arr = [100,200,300,400];
    const obj = { addr:'北京' , phone : 123456 , email:'123@qq.com' };

    function fa1(){};
    function fa2(){};
    function fa3(){};

    // 当前模块导出数据
    module.exports = { name , age , sex  , arr , obj , fa1 , fa2 , fa3 };

})

依赖模块

// 依赖模块 
// 依赖模块A的数据
define(function( require , exports , module ){
    // 导入 模块A 的数据 
    const valA = require('./a.js');

    
    let name = '李四' ;
    let age = valA.age - 5 ;
    let sex = '女' ;

    const arr = valA.arr.map( item => {

        return item / 100 ;

    })

    const obj = valA.obj ;

    function fb1 (){}
    function fb2 (){}
    function fb3 (){}
    function fb4 (){}

    // 导入当前模块的数据
    module.exports = { name , age , sex , arr , obj , fb1 , fb2 , fb3 , fb4 };
});

整合模块

// 整合模块
// 整合模块A 和 模块B 的数据和函数方法
seajs.use( ['./a.js' , './b.js'] , function( valA , valB ){
    // 参数 valA 存储 第一个文件 模块A 导出的数据
    // 参数 valB 存储 第二个文件 模块B 导出的数据

    console.log( valA );
    console.log( valB );

})