JavaScript 模块化开发历程

# JavaScript 模块化开发


方式简单化实现
    + 模块与模块之间相互协作构成了模块系统




- 程序模块化开发的优点
    + 开发效率高
        * 代码方便重用,别人开发的模块直接拿过来就可以使用,不需要重复开发类似的功能
    + 可维护性高
        * 软件的声明周期中最长的阶段其实并不是开发阶段,而是维护阶段,
需求变更比较频繁,使用模块化的开发方式更容易维护




历史上,JavaScript一直没有模块体系,
无法将一个大程序拆分成相互依赖的小文件,再用简单的方法拼接起来
其他语言,包括CSS都有这项功能,
但是JavaScript任何这方便的支持都是没有的,这对开发大型的、复杂的项目形成了障碍


## 02-Nodejs铺垫-模块化演变历程-全局函数


- 全局函数
    + 全局函数形成的模块只能人为的认为他们属于一个模块
    + 但是程序并不能区分哪些函数是同一个模块


- 全局函数容易造成的问题
    + 污染了全局变量,无法保证不与其他模块发生变量名冲突
    + 从代码阅读上来说:模块成员之间看不出之间的关系




## 03-Nodejs铺垫-模块化演变历程-对象封装 (命名空间法)


所谓的命名空间,就是对象上加了一个属性或者方法


- 对象封装-命名空间
    + 通过添加命名空间的形式从某种程度上解决了变量命名冲突的问题,但是并不能从根本上解决命名冲突
    + 从代码级别可以明显的区别出哪些函数属于同一模块
- 对象封装-命名空间造成的问题
    + 暴露了所有的模块成员,内部状态可以被外部改写,不安全
    + 命名空间越来越长



## 04-Nodejs铺垫-模块化演变历程-隔离公有私有成员 (私有空间)(重要)


☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆


如果不通过return,外部是无法访问到内部的属性和方法的,无法修改


形成了一个隔离作用域,
可以把模块自己使用的成员封装到模块内部,降低了对全局作用域的污染
其实就是降低命名冲突的概率,隔离公有私有成员



通过匿名自执行函数,利用函数作用域的机制隔开私有变量


- 私有共有成员分离
    + 私有空间的变量和函数不会影响全局作用域
    + 公开公有方法,隐藏私有空间


var on = (function(){
    1、私有的函数
    2、公有的部分
    return
})()




## 05-Nodejs铺垫-模块化演变历程-增强模块可维护性(了解,多写熟悉)


- 模块的维护和拓展
    + 可以采用直接赋值的形式扩展这个模块,防止了模块的名称被冲突
    + 在加载模块的时候,不需要在考虑顺序的问题,但是采用着这种方式,一定要遵守这种规范


开闭原则


    var on = (function(){
        1、私有的函数
        2、公有的部分
        return
    })()


    var on = (function(o){
        1、私有的函数
        2、公有的部分
        return
    })(one || {})


## 06-Nodejs铺垫-模块化演变历程-添加第三方依赖


一定要把依赖项通过参数的形式注入进来,然后在内部使用注入的属性

不要直接在模块内部使用第三方依赖


- 模块的第三方依赖
    + 模块最好要保证模块的职责单一性,最好不要与程序的其他部分直接交互
    + 通过向匿名函数注入依赖项的形式,除了保证模块的独立性,还使模块之间的依赖关系变的更加明显


- 好处
    + 提高了代码的执行性能,减少了变量作用域的查找层数
    + 增加了代码的可读性,能直观的看当前文件模块依赖的其他模块




    var on = (function(o, abc){
        1、私有的函数
        2、公有的部分
        return
    })(one || {}, jQuery)


##  上面几种模块化演变历程方法的总结


- 规范
    + 最大的问题,还是规范的问题
    + 如果在多人协作开发过程中,会有很大的问题
    + 多人协作开发阶段:代码的风格一定要统一


## 07-Nodejs铺垫-初识模块化框架Seajs


- 简单介绍一下这些标准
    + CMD
        * seaJS
        * 玉伯
    + AMD
        * requireJS


    + commonJS


## 08-Nodejs铺垫-Seajs基本使用


- 使用seajs的步骤
    + 1、引入seajs
    + 2、如何定义模块
        * define // 参数的名字不允许修改,参数可以是多个
        * define(function(require, exports, module){});
    + 3、如何公开模块成员
        * exports
        * seajs.use两个参数
            - 模块的路径
            - 回调函数 -- 回调函数的参数指成的是exports
    + 4、如何依赖模块
        * require()


## 09-Nodejs铺垫-Seajs模块定义参数分析


- exports 与 module.exports
    + 它们两个实际上是一个对象
    + exports 对外提供接口
    + module.exports 对外提供了整个接口


- require
    + 加载外部的模块
    + require 是一个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口。
- exports
    + exports 是一个对象,用来向外提供模块接口。
- module
    + module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。


- module有几种属性和方法
    + module.id (模块id,就是全路径了,一般情况下(没有在 define 中手写 id 参数时),module.id 的值就是 module.uri,两者完全相同。)  
    + module.exports(对外接口,{}格式,exports 仅仅是 module.exports 的一个引用。)
    + module.dependencies(数组,当前模块依赖的模块)




## 10-Nodejs铺垫-Seajs模块导出成员原理分析(重要)
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆


exports 与 module.exports 的区别


 其实,Module.exports才是真正的接口,exports只不过是它的一个辅助工具。
 最终返回给调用的是Module.exports而不是exports。
 所有的exports收集到的属性和方法,都赋值给了Module.exports。
 当然,这有个前提,就是Module.exports本身不具备任何属性和方法。
 如果,Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略



- 如果导出的是单个成员,那么一般使用exports.成员名称 这种形式导出
- 如果导出的是一个对象,那么一般使用module.exports这种形式导出


## 11-Nodejs铺垫-Seajs异步加载模块


Seajs异步加载模块的写法
> require.async("模块地址",function(){})


require.async('./')


## 12-Nodejs铺垫-Seajs依赖jQuery


- 如何设置jQuery依赖
```js
    if ( typeof noGlobal === strundefined ) {
        window.jQuery = window.$ = jQuery;
        if ( typeof define === "function" ) {
            define(function(){return jQuery});
        }
    }
```
- seaJS如何配置参数
```js
    seajs.config({
        alias : {
            jquery : "jquery-1.11.1.js"
        }
    })
```
- module参数
    + id:模块的唯一标识
    + uri: 模块绝对路径
    + dependencies:当前模块依赖
    + exports:当前模块对外接口


### 开闭原则


- 模块拓展一定需要遵守的原则
    + 对添加开放
    + 对修改封闭


### ConmonJS 规范
> CommonJS 规范不是专门为JavaScript模块化制定的规范,

> 而是为JavaScript语言很多在后台没有没有实现的功能制定的API规范

> 例如:文件操作、网络操作、进程操作等接口API  

> 为JavaScript语言本身在后台的功能实现定义了很多API,其中就包括模块化的规范API


- 一个单独的文件就是一个模块
- 所有代码都运行在模块作用域中,不会污染全局作用域
- 每个文件的对外接口是module.exports对象
- require命令用于加载模块文件的接口对象
- 模块可以加载多次,但是只会在第一次加载的时候运行一次,然后运行结果就被缓存了,以后在加载,就直接读取缓存结果
- 模块加载的顺序,按照其在代码中出现的顺序


### CMD、AMD、ConmonJS的区别


- AMD
    + 预加载,预执行
    + 预加载就是把所有的 js 文件模块都下载下来
    + 预执行就是把每个加载成功一个执行一个




- CMD
    + 预加载,懒执行
    + 预加载就是把所有的 js 文件模块都下载下来
    + 懒执行就是等所有的js文件都加载完毕之后了才去执行




- ConmonJS
    + 执行到了哪里,就加载到哪里,然后执行哪里,
    + 同步加载,同步执行
















你可能感兴趣的:(JavaScript 模块化开发历程)