模块化

*解析

模块是可以实现特定功能的一组代码。

由于JS不能handle超大规模代码,所以要借鉴其它语言处理这种问题的方式:
把逻辑相关的代码组织到同一个区域,区域内部相对独立和外界互不干扰;
外部使用时直接引用对应的区域即可。

模拟类似的功能,用来隔离、组织复杂的JavaScript代码,我们称为模块化。

*作用

1 解决命名冲突
2 解决互相依赖
3 提高代码的可读性
4 提高代码的复用性

*规范

**CommonJS

解析:
服务器端使用的模块规范 例如 Node.js

使用:
1 定义模块 一个文件 = 一个模块 = 一个单独的作用域
2 模块输出: 唯一出口module.exports对象,存放输出内容
3 加载模块: 使用require方法读取文件并执行,返回ta内部的module.exports对象

举例:                      
  
Model-1.js                    1 定义模块
    var name = 'jrg';           
    function a(){...}             name是模块的内部变量,只有文件内的函数可以使用
    function b(){...}                            
    module.exports={          2 模块输出 (导出接口)
        a:a,
        b:b
    }

Model-2.js                        *新模块 = 新文件
    function c(){...}
    module.exports = c


main.js                       3 加载模块                              
    var xx = require('./Model-1');
    var dd = require('./Model-2');  使用哪个模块再引入                        
    xx.a()                      
    dd.c()                          然后就可以调用模块提供的方法

**问题

Q CommonJS 规范在服务器端这么方便,那么浏览器端可以用吗?
A NO!
R 服务器端的文件在本地 => 同步加载;浏览器端的文件在远程服务器 =>异步加载
····所以CommonJS模块在浏览器环境中无法正常加载。
····浏览器端需要另外的规范来封装模块 => AMD & CMD

**AMD

解析:
浏览器端使用的模块规范之一 Asynchronous Module Definition异步模块定义

define函数,定义模块-------------------------------------------------- 

语法: 
    define(id?, dependencies?, factory)

参数:
    id:模块名;如果没有参数,默认为文件名。
    dependencies:一个数组;当前模块 [依赖的模块名称集合]。
    factory:工厂函数;模块初始化要执行的函数(只执行一次) or 对象(模块的输出值)。


 require函数,加载模块-------------------------------------------------

 语法:  require([dependencies], function(){});

 参数:  [dependencies]是一个数组,表示所依赖的模块;
         function(){} 是一个回调函数,当前面指定的模块都加载成功后,以参数形式传入该函数,
                      然后函数内部就可以使用这些模块了。

 
 举例----------------------------------------------------------------------------

 myModule1.js    定义模块 
     define(['dependency'], function(){      
         function a(){...} // 使用面向对象方式封装好的组件
         return a,        //  留出接口
     });

 main.js      加载模块  
     require(['myModule1','myModule2'], function (myModule1,myModule2){    
          myModule1.a();      // 调用组件
     });

**CMD

解析:
国内发展出来的模块规范Common Module Definition通用模块定义

define函数,定义模块---------------------------------------------------------

语法:               
    define(function(require, exports, module){ });

参数:    
   require 是一个方法,获取其他模块的接口
   exports 是一个对象,向外提供模块接口
   module 是一个对象,存储了一些属性和方法

举例--------------------------------------------------------------------------

 ModuleA.js     定义模块 
   define(function(require, exports, module) {    function的三个参数固定不变 
     var a = require('a.js')                       函数内部,用到谁就引入谁
     a();                                          写法类似commonJS
     ModuleA.exprots = xx;
   });

main.js       加载模块  
   seajs.use(['ModuleA.js'], function(ModuleA){ ... });

模块化工具:
▶由于不是JavaScript原生支持,
使用AMD需要用到对应的库函数RequireJS
使用CMD需要用到对应的库函数SeaJS
其实AMDCMD分别 是RequireJSSeaJS 在推广过程中对模块定义的规范化产出;
同样倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。

AMDCMD的区别?
** 1** 关于依赖的模块,加载都是异步,执行处理不同
AMD:推崇依赖前置,提前执行(依赖先执行)
CMD:推崇依赖就近,延迟执行(运行到需加载,根据顺序执行)
** 2** 关于API
AMD:API根据使用范围有区别,但使用同一个api接口
CMD:每个API的职责单一

**requireJS

requireJS主要解决两个问题:
1 实现js文件的异步加载,避免网页失去响应;
2 管理模块之间的依赖性,便于代码的编写和维护。

如果
   不使用`requireJS`就要单独加载每个js文件,像这样:
   
   
   
 缺点
   1 加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;
   2 由于js文件之间存在依赖关系,因此必须严格保证加载顺序,依赖性最大的模块必须放到最后,
     当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

**总结

至此,已经了解模块规范,可以写出符合规范的 模块文件了!
以AMD为例,梳理一下使用过程:

1 下载require.js文件,放入根目录
2 页面引入requireJS库 => 主文件
3 页面引入主文件 => 加载模块
4 主文件 => 已放入根目录的模块文件
Tip:
主文件=>加载模块=>require函数=>语法require([dependencies], function(){})
模块文件=>定义模块=>define函数=>语法define([dependencies], factory)

**r.js

这是一个打包工具

作用
把所有的模块和框架js文件压缩到同一个js文件里,
Before: 引入requireJS库=>引入主文件=>查找模块
After : 引入requireJS库=>查找模块

使用
1 下载r.js文件,放入根目录
2 配置压缩文件build.js
3 打开node,进入目标DEMO-AMD
4 执行命令行node r.js -o build.js,会自动生成压缩文件
5 将页面上的主文件地址main.js替换为压缩后的文件index.merge.min.js

*应用

Demo

▼DEMO-AMD   
   ▶index.html   
   ▶CSS              
   ▼JS
     ▼lib            框架&库目录
       ▷require.js
       ▷r.js
       ▷jquery.js
        ......
     ▼app            组件目录
       ▷gotop.js
        ......
     ▶main.js       主文件
     ▶build.js      压缩配置文件

     ▼dist          输出目录
       ▷index.merge.min.js   


   ■ index.html
    页面加载 
    □ src       先加载库 => 执行require.js => 解析后指向主文件  
    □ data-main 自定义属性 => 执行main.js  =>  主文件里是所有模块的入口


   ■ main.js                主文件 =>
     requirejs.config({              □ 配置路径,方便查找
         baseUrl: "./js/app",             默认文件夹(加载时写直接写里面的模块名)
         paths: {                         特殊文件/夹(相对于baseUrl)
             'jquery': '../lib/jquery'        指向模块  (加载时写模块名)
             'lib':'../lib'                   指向文件夹(加载时写lib下模块名)
         }                                  
     });
     requirejs(["GoTop","lib/xx",...],
     function(GoTop,$,...) {         □ 加载([依赖模块],工厂函数)
         new GoTop();                          模块加载完毕,作为参数传入工厂函数
         ......                                 执行工厂函数
     });

    ● 这里的baseUrl是main.js相对于index.html=> 从index出发找到app
    ● requirejs(["xxx"]) => 如果没有工厂函数,直接加载并执行文件


   ■ build.js             压缩配置文件 =>  
     ({                                □ 配置路径   
         baseUrl: ".",                       两个baseUrl指向要保持一致(都指向app)  
         paths: {
             'jquery': './lib/jquery',
             'GoTop':'./com/GoTop',
             ......
         },
         name: "main",                       配置入口
         out: "./dist/index.merge.min.js"    配置出口(自定义)
     });

    ● 这里的baseUrl是build.js相对于自身的,=> 从build 出发找到 app

参考 详解JavaScript模块化开发

但是!程序员永远有更便捷的方法 => webpack

你可能感兴趣的:(模块化)