ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JS模块化

2022-01-25 23:33:20  阅读:190  来源: 互联网

标签:reset count const 模块化 require JS increase js


一、什么是模块化

       在js出现的时候,js一般只是用来实现一些简单的交互,后来js开始得到重视,用来实现越来越复杂的功能,而为了维护的方便,我们也把不同功能的js抽取出来当做一个js文件,但是当项目变的复杂的时候,一个html页面可能需要加载好多个js文件,而这个时候就会出现各种命名冲突,如果js也可以像java一样,把不同功能的文件放在不同的package中,需要引用某个函数或功能的时候,import下相关的包,这样可以很好的解决命名冲突等各种问题,但是js中没有模块的概念,又怎么实现模块化呢

  模块化开发是一种管理方式,是一种生产方式,一种解决问题的方案,一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块,但是模块开发需要遵循一定的规范,否则就都乱套了,因此,才有了后来大家熟悉的AMD规范,CMD规范

二、JS模块发展背景

    1)幼年期(也就是无模块化)

            1.开始需要在页面中增加一些不同的js:动画、表单、格式化

            2.多种js文件被分在不同的文件中

            3.不同的文件又被同一个模板引用(文件分离是最基础的模块化第一步)

  <script src="jquery.js"></script>
  <script src="main.js"></script>
  <script src="dep1.js"></script>
  //……

            4.出现的问题:污染全局作用域 => 不利于大型项目的开发以及多人团队的共建

     2)成长期(模块化的雏形 - IIFE(语法侧的优化) )

       IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的  JavaScript 函数

      1.作用域的把控

  // 定义一个全局变量
  let count = 0;
  // 代码块1
  const increase = () => ++count;
  // 代码块2
  const reset = () => {
    count = 0;
  }

  increase();
  reset();

       2.利用函数块级作用域

(()=>{
    let count = 0;
    //...
  })

       3.仅定义了一个函数 如果立即执行,就在函数后加(),表示立即执行

(() => {
    let count = 0;
    // ……
  }();

  以上步骤,仅是初步实现了一个最最简单的模块.

  下面,尝试去定义一个最简单的模块

const iifeModule = (() =>{
  let count = 0;
  return {
    increase: () => ++count;
    reset: () => {
      count = 0;
    }
  }
})();

iifeModule.increase();
iifeModule.reset();

      4.相关问题

        1)有额外依赖时,如何优化IIFE相关代码?

           答:依赖其他模块的IIFE

const iifeModule = ((dependencyModule1, dependencyModule2) => { //dependencyModule即为其他模块
  let count = 0;
  return {
    increase: () => ++count;
    reset: () => {
      count = 0;
    }
  }
})(dependencyModule1, dependencyModule2);
iifeModule.increase();
iifeModule.reset();

       2)了解早期jquery的依赖处理以及模块加载方案吗?/ 了解传统IIFE是如何解决多方依赖的问题

          答:IIFE加传参调配

  实际上 JQuery框架其实应用了revealing(揭露)的写法

const iifeModule = ((dependencyModule1, dependencyModule2) => {
  let count = 0;
  const increase = () => ++count;
  const reset = () => {
    count = 0;
  }

  return {
    increase, reset
  }
})(dependencyModule1, dependencyModule2);
iifeModule.increase();
iifeModule.reset();

    3)成熟期( Commonjs(CJS) )

             由node.js制定

             特征:1.通过 module + exports 去对外暴露接口

                     2.通过 require 来调用其他模块

      1.模块组织方式:

        1).main.js文件

// 引入部分
const dependencyModule1 = require(./dependencyModule1);
const dependencyModule2 = require(./dependencyModule2);

// 处理部分
let count = 0;
const increase = () => ++count;
const reset = () => {
  count = 0;
}
// 做一些跟引入依赖相关事宜……

// 暴露接口部分
exports.increase = increase;
exports.reset = reset;

module.exports = {
  increase, reset
}

        2).模块使用方式( require 调用即可 )

  const { increase, reset } = require('./main.js');

  increase();
  reset();

       2.CJS优缺点

  •    优点:CommonJS率先在服务端实现了,从框架层面解决依赖、全局变量污染的问题
  •    缺点:主要针对了服务端的解决方案。对于异步拉取依赖的处理整合不是那么的友好

那么在此产生了新的问题 ----- 异步依赖 ,就需要AMD来解决

 三、AMD规范

            方法:通过异步加载 和 允许制定回调函数

            经典实现框架: require.js

      1)新增定义方式

                通过 define 来定义一个模块,然后 require 进行加载
           

//params: 模块名,依赖模块,工厂方法  
  define(id, [depends], callback);
  require([module], callback);

      2)模块定义方式

  define('amdModule', ['dependencyModule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => {
    // 业务逻辑
    // 处理部分
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
      count = 0;
    }

    return {
      increase, reset
    }
  })

      3)引入模块

  require(['amdModule'], amdModule => {
    amdModule.increase();
  })

      4)相关问题

          1.如果在AMDmodule中想兼容已有代码,如何做?

  define('amdModule', [], require => {
    // 引入部分
    const dependencyModule1 = require(./dependencyModule1);
    const dependencyModule2 = require(./dependencyModule2);

    // 处理部分
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
      count = 0;
    }
    // 做一些跟引入依赖相关事宜……

    return {
      increase, reset
    }
  })

        2.AMD中使用revealing

  define('amdModule', [], (require, export, module) => {
    // 引入部分
    const dependencyModule1 = require(./dependencyModule1);
    const dependencyModule2 = require(./dependencyModule2);

    // 处理部分
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
      count = 0;
    }
    // 做一些跟引入依赖相关事宜……

    export.increase = increase();
    export.reset = reset();
  })

  define('amdModule', [], require => {
    const otherModule = require('amdModule');
    otherModule.increase();
    otherModule.reset();
  })

        3.兼容AMD&CJS / 如何判断CJS和AMD UMD的出现

(define('amdModule', [], (require, export, module) => {
    // 引入部分
    const dependencyModule1 = require(./dependencyModule1);
    const dependencyModule2 = require(./dependencyModule2);

    // 处理部分
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
      count = 0;
    }
    // 做一些跟引入依赖相关事宜……

    export.increase = increase();
    export.reset = reset();
  }))(
    // 目标是一次性区分CommonJSorAMD
    typeof module === "object"
    && module.exports
    && typeof define !== "function"
      ? // 是 CJS
        factory => module.exports = factory(require, exports, module)
      : // 是AMD
        define
  )

      5)AMD优缺点

  •     优点:适合在浏览器中加载异步模块,可以并行加载多个模块
  •     缺点:会有引入成本,不能按需加载

四、CMD规范

按需加载

主要应用框架:sea.js

  define('module', (require, exports, module) => {
    let $ = require('jquery');
    // jquery相关逻辑

    let dependencyModule1 = require('./dependecyModule1');
    // dependencyModule1相关逻辑
  })

CMD优缺点: 

  •      优点:按需加载,依赖就近
  •      缺点:依赖于打包,加载逻辑存在于每个模块中,扩大模块体积

相关问题: AMD & CMD 的区别

                答:依赖就近,按需加载

五、ES6模块化

      1)新增定义

                引入关键字 ---- import

                导出关键字 ---- export

      2)模块引入、导出和定义的地方

  // 引入区域
  import dependencyModule1 from './dependencyModule1.js';
  import dependencyModule2 from './dependencyModule2.js';

  // 实现代码逻辑
  let count = 0;
  export const increase = () => ++count;
  export const reset = () => {
    count = 0;
  }

  // 导出区域
  export default {
    increase, reset
  }

      3)模板引入的地方

  <script type="module" src="esModule.js"></script>

      4)在node中

  import { increase, reset } from './esModule.mjs';
  increase();
  reset();

  import esModule from './esModule.mjs';
  esModule.increase();
  esModule.reset();

      5)相关问题

                ES6中的动态模块是哪些?

                答: export 和 promise

      6)ES11原生解决方案(包含了 promise)

  import('./esModule.js').then(dynamicEsModule => {
    dynamicEsModule.increase();
  })

      7)ES6模块化优缺点          

  • 优点(重要性):通过一种最统一的形态整合了js的模块化

  • 缺点(局限性):本质上还是运行时的依赖分析

六、解决模块化的新思路 - 前端工程化

     1)背景

               根本问题 - 前端的模块化处理方案依赖于运行时分析

     2)问题解决方案

                线下执行  grunt gulp webpack......

  <!doctype html>
    <script src="main.js"></script>
    <script>
      // 给构建工具一个标识位
      require.config(__FRAME_CONFIG__);
    </script>
    <script>
      require(['a', 'e'], () => {
        // 业务处理
      })
    </script>
  </html>
  define('a', () => {
    let b = require('b');
    let c = require('c');

    export.run = () {
      // run
    }
  })

     3)工程化实现(思路)

               1.扫描依赖关系表

  {//a b e的全局依赖
    a: ['b', 'c'],
    b: ['d'],
    e: []
  }

               2.重新生成依赖数据模板

  <!doctype html>
    <script src="main.js"></script>
    <script>
      // 构建工具生成数据
      require.config({
        "deps": {
          a: ['b', 'c'],
          b: ['d'],
          e: []
        }
      })
    </script>
    <script>
      require(['a', 'e'], () => {
        // 业务处理
      })
    </script>
  </html>

             3.执行工具,采用模块化方案解决模块化处理依赖

define('a', ['b', 'c'], () => {
    // 执行代码
    export.run = () => {}
  })

     4)工程化实现优点

  • 构建时生成配置,运行时执行
  • 最终转化成执行处理依赖
  • 可以拓展

七、最终的完全体

       webpack(核心的工程化)+ mvvm框架组件化 + 设计模式 

标签:reset,count,const,模块化,require,JS,increase,js
来源: https://blog.csdn.net/qq_45812558/article/details/122691906

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有