zoukankan      html  css  js  c++  java
  • js模块化规范—概念和模块化进化史以及模块化的问题

    模块的概念

    一个复杂的项目开发中,会写很多js文件,一个js文件执行某些特定的功能,那么每个js都可以称为一个模块,这就是模块的概念

    每个js模块内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信

    模块化的进化史

    全局function模式:将不同的功能封装成不同的全局函数

    问题: Global被污染了, 很容易引起命名冲突

    //数据
    let data = 'atguigu.com'
    
    //操作数据的函数
    function foo() {
      console.log(`foo() ${data}`)
    }
    function bar() {
      console.log(`bar() ${data}`)
    }
    let data2 = 'other data';
    
    function foo() {  //与另一个模块中的函数冲突了
      console.log(`foo() ${data2}`)
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>01_全局function模式</title>
    </head>
    <body>
    <script type='text/javascript' src='module1.js'></script>
    <script type='text/javascript' src='module2.js'></script>
    <script type='text/javascript'>
       let data = "修改后的数据" // 模块1中已经定义了data变量,重复定义同名变量报错
       foo() // module2模块中的foo()方法覆盖了module1模块中的foo()方法
       bar()
    </script>
    </body>
    </html>

    namespace模式

    简单对象封装,减少了全局变量
    问题: 不安全(数据不是私有的, 外部可以直接修改)

    let myModule1 = {
      data: 'atguigu.com',
      foo() {
        console.log(`foo() ${this.data}`)
      },
      bar() {
        console.log(`bar() ${this.data}`)
      }
    }
    let myModule2 = {
      data: 'atguigu.com2222',
      foo() {
        console.log(`foo() ${this.data}`)
      },
      bar() {
        console.log(`bar() ${this.data}`)
      }
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>02_namespace模式</title>
    </head>
    <body>
    <script type="text/javascript" src="module1.js"></script>
    <script type="text/javascript" src="module2.js"></script>
    <script type="text/javascript">
      myModule1.foo() // foo() atguigu.com
      myModule1.bar() // bar() atguigu.com
    
      myModule2.foo() // foo() atguigu.com2222
      myModule2.bar() // bar() atguigu.com2222
    
      myModule1.data = 'other data' //能直接修改模块内部的数据
      myModule1.foo() // foo() other data
    
    </script>
    </body>
    </html>

    IIFE模式: 匿名函数自调用(闭包)
    IIFE : immediately-invoked function expression(立即调用函数表达式)
    作用: 数据是私有的, 外部只能通过暴露的方法操作
    问题: 如果当前这个模块依赖另一个模块怎么办

    (function (window) {
      let data = 'atguigu.com' // 数据
    
      //操作数据的函数
      function foo() { //用于暴露有函数
        console.log(`foo() ${data}`)
      }
    
      function bar() {//用于暴露有函数
        console.log(`bar() ${data}`)
        otherFun() //内部调用
      }
    
      function otherFun() { //内部私有的函数
        console.log('otherFun()')
      }
      //暴露行为
      window.myModule = {foo, bar}
    })(window)
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>03_IIFE模式</title>
    </head>
    <body>
    <script type="text/javascript" src="module3.js"></script>
    <script type="text/javascript">
      myModule.foo() // foo() atguigu.com
      myModule.bar() // bar() atguigu.com
      //myModule.otherFun()  //myModule.otherFun is not a function
      console.log(myModule.data) //undefined 不能访问模块内部数据
      myModule.data = 'xxxx' //不能修改的模块内部的data,这只是给myModule对象增加了一个data属性
      myModule.foo() // 没有改变,foo() atguigu.com
    
    </script>
    </body>
    </html>

    IIFE模式增强 : 引入依赖

    这就是现代模块实现的基石

    (function (window, $) {
      let data = 'atguigu.com' // 数据
    
      // 操作数据的函数
      function foo() {  // 用于暴露有函数
        console.log(`foo() ${data}`)
        $('body').css('background', 'red')
      }
    
      function bar() {  // 用于暴露有函数
        console.log(`bar() ${data}`)
        otherFun() // 内部调用
      }
    
      function otherFun() { //内部私有的函数
        console.log('otherFun()')
      }
    
      //暴露行为
      window.myModule = {foo, bar}
    })(window, jQuery)
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>04_IIFE模式增强</title>
    </head>
    <body>
    <!--引入的js必须有一定顺序-->
    <script type="text/javascript" src="jquery-1.10.1.js"></script>
    <script type="text/javascript" src="module4.js"></script>
    <script type="text/javascript">
      myModule.foo() // foo() atguigu.com
    </script>
    </body>
    </html>

    为什么要模块化开发

    首先来说明一下,项目中js为什么要模块化的开发,当项目开发越来越复杂的时候,会经常遇到代码冲突,每个js文件之间的依赖关系,当js文件越来越多的时候页面加载性能等等一些问题

    代码冲突:比如在团队协作的过程中,同事A写了一个组件库common的一个js文件,里面有个操作选项卡的一个函数叫做tab,然后同事B在同一个页面中进行修改的时候,也定义了一个叫做tab的函数,那这个时候,这两个方法就冲突了(不仅函数冲突,包括变量等等),一般情况下,简单的解决方案就是给这些函数或者变量加上命名空间(这个解决方案的缺点是名字比较长 , 只能降低冲突,不能完全避免)

    var above = {};  //名字比较长 , 只能降低冲突,不能完全避免
    
    above.a = 10;
    
    above.tab = function(){};
    
    above.drag = function(){};
    
    above.dialog = function(){};
    
    //调用的时候需要加上前缀,如果命名空间比较长的时候,调用的时候更加麻烦
    above.tab();

    多个js文件之间的依赖关系:当项目越来越大的时候,项目需要将js进行分层,当a.js和b.js两个文件都需要引入页面中,并且b.js需要依赖a.js的时候,当时后期项目需求更改需要加入一个功能,在写一个c.js文件,需要依赖a.js,当越来越多文件,文件之间有相互依赖的关系,如果少了某个依赖的文件那么页面就出错了

    模块化的好处和问题

    避免命名冲突(减少命名空间污染),更好的分离, 按需加载,更高复用性,高可维护性

    模块化能带来很多好处,但现实开发中也会带来问题

    页面引入加载script,产生的问题:请求过多,依赖模糊,难以维护,所以我们需要一些模块化的规范来解决这些问题

    SeaJs简介

    Seajs库的作用就是为了解决代码冲突,js模块的依赖关系等等问题

    Seajs,一个Web模块加载框架,追求简单、自然的代码书写和组织方式,:Sea.js 遵循 CMD 规范,模块化JS代码。依赖的自动加载、配置的简洁清晰,可以让程序员更多地专注编码。

    Seajs优缺点

    优点:提高可维护性、模块化编程、动态加载,前端性能优化

    缺点:学习文档偏少且混乱,会更改团队使用JS的编写习惯,必须使用模块化编程。不太适合团队目前的情况,多JS文件但少改动,动态加载优势和模块化优势不明显。需要配套使用SPM工具,JS的打包和管理工具
     
     
     

    SeaJs与JQuery的区别

    什么是CMD 和AMD

    异步模块定义(AMD)是Asynchronous Module Definition的缩写,是 RequireJS 在推广过程中对模块定义的规范化产出。
    通用模块定义(CMD)是Common Module Definition的缩写,是SeaJS 在推广过程中对模块定义的规范化产出。
    RequireJS 和 SeaJS 都是模块化框架的代表,AMD和CMD,是他们各自定义模块化的方式,大同小异,主要是代码风格和API不同
     
     
     
     
  • 相关阅读:
    单元測试和白盒測试相关总结
    数据结构:图的实现--邻接矩阵
    Android提示版本号更新操作流程
    《集体智慧编程》代码勘误:第六章
    LINUX设备驱动程序笔记(三)字符设备驱动程序
    数学定理证明机械化的中国学派(II)
    《Java并发编程实战》第三章 对象的共享 读书笔记
    Linux系列-安装经常使用软件
    Kubuntu 初始配置
    虚拟互换(virtual swap)
  • 原文地址:https://www.cnblogs.com/LO-ME/p/7507146.html
Copyright © 2011-2022 走看看