js模块化开发学习

模块化开发理解

Javascript模块化编程,主要用于实现开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块。

模块就是实现特定功能的一组方法。有了模块,我们就可以方便的使用别人的代码,需要什么功能,就加载相应的模块。

一个模块其实就是一个实现特定功能的文件,这个文件中封装了一些函数和变量。每个模块都提供了对外访问的接口,使得使用者可以方便的调用模块里面封装的方法。

有了模块,我们就可以更方便地使用别人的代码,需要什么函数来实现指定功能,就加载相应的模块就可以了。模块开发需要大家按照同样的方式来编写模块,否则就都乱套了。

目前,通用的js模块规范有:AMD(Asynchronous Module Definition 异步模块定义)、CMD(Common Module Definition) 通用模块定义commonJS。其中AMD和CMD是浏览器端模块化开发的规范,commonJS是服务器端的规范。

AMD规范

该规范通过define方法来定义模块,require方法来调用模块,实现代码的模块加载。模块将被异步加载模块加载不影响后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

AMDRequireJS 在推广过程中对模块定义的规范化的产出。

AMD就只有一个接口:define(id?,dependencies?,factory);
它要在声明模块的时候制定所有的依赖(dep),并且还要当做形参传到factory中,像这样:

define(['dep1','dep2'],function(dep1,dep2){...});

要是没什么依赖,就定义简单的模块,下面这样就可以啦:

define(function(){
    var exports = {};
    exports.method = function(){...};
    return exports;
});

RequireJS学习

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>require</title>
    </head>
    <body>
    <script type="text/javascript" src="js/require.js" data-main="js/main.js"></script>
    </body>
</html>

主模块main.js,是整个页面的入口代码

//main.js是主模块,主模块需要依赖其他模块来进行工作
//alert("加载成功");
require(['math','sorts'],function(math,sorts){
    console.log(math.add(10,12));
    console.log(math.chu(24,12));
    console.log([1,5,4,3,2].sort(sorts.compare));
});

其他模块

sorts.js

define(function(){
    var compare=function(num1,num2){
        if(num1<num2){
            return -1;
        }else if(num1>num2){
            return 1;
        }else{
            return 0;
        }
    };
    return {
        compare:compare
    };
});

//math.js
define(function(){
    var add=function(x,y){
        return x+y;
    };
    var chu=function(x,y){
        return x/y;
    };
    return {
        add:add,
        chu:chu
    };
});
require()函数接受两个参数。第一个参数是一个数组,表示主模块所依赖的模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。主模块的代码就写在回调函数中

require()异步加载所需模块,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

require.config配置

require.config是用来配置模块加载位置,简单点说就是给模块起一个更短更好记的名字,比如将百度的jquery库地址标记为jquery,这样在require时只需要写["jquery"]就可以加载该js,本地的js我们也可以这样配置:
require.config({
    paths : {
        "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery"],
        "a" : "js/a"   
    }
})
require(["jquery","a"],function($){
    $(function(){
        alert("load finished");  
    })
})

通过paths的配置会使我们的模块名字更精炼,paths还有一个重要的功能,就是可以配置多个路径,如果远程cdn库没有加载成功,可以加载本地的库,如:
require.config({
    paths : {
        "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
        "a" : "js/a"   
    }
})
require(["jquery","a"],function($){
    $(function(){
        alert("load finished");  
    })
})

这样配置后,当百度的jquery没有加载成功后,会加载本地js目录下的jquery.在使用requirejs时,加载模块时不用写.js后缀的,当然也是不能写后缀

全局配置

上面的例子中重复出现了require.config配置,如果每个页面中都加入配置,必然显得十分不雅,requirejs提供了一种叫"主数据"的功能,我们首先创建一个main.js:
require.config({
    paths : {
        "jquery" : ["http://libs.baidu.com/jquery/2.0.3/jquery", "js/jquery"],
        "a" : "js/a"   
    }
})

然后再页面中使用下面的方式来使用requirejs:
<script data-main="js/main" src="js/require.js"></script>
加载requirejs脚本的script标签加入了data-main属性,这个属性指定的js将在加载完reuqire.js后处理,我们把require.config的配置加入到data-main后,就可以使每一个页面都使用这个配置,然后页面中就可以直接使用require来加载所有的短模块名
data-main还有一个重要的功能,当script标签指定data-main属性时,require会默认的将data-main指定的js为根路径。如上面的data-main="js/main"设定后,我们在使用require(['jquery'])后(不配置jquery的paths),require会自动加载js/jquery.js这个文件,而不是jquery.js。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

加载非规范的模块

这样的模块在用require()加载之前,要先用require.config()方法,定义它们的一些特征。
举例来说,underscore和backbone这两个库,都没有采用AMD规范编写。如果要加载它们的话,必须先定义它们的特征。
require.config({
    shim: {
      'underscore':{
        exports: '_'
      },
      'backbone': {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      }
    }
  });
require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义(1)exports值(输出的变量名),表明这个模块外部调用时的名称;(2)deps数组,表明该模块的依赖性。

jQuery的插件可以这样定义:

shim: {
    'jquery.scroll': {
      deps: ['jquery'],
      exports: 'jQuery.fn.scroll'
    }
  }

require.js插件

domready插件,可以让回调函数在页面DOM结构加载完成后再运行。
require(['domready!'], function (doc){
    // called once the DOM is ready
  });

text和image插件,则是允许require.js加载文本和图片文件。
define([
    'text!review.txt',
    'image!cat.jpg'
    ],

    function(review,cat){
      console.log(review);
      document.body.appendChild(cat);
    }
  );

类似的插件还有json和mdown,用于加载json文件和markdown文件。

CMD规范

CMD(Common Module Definition) 通用模块定义。该规范明确了模块的基本书写格式和基本交互规则。该规范是在国内发展出来的。AMD是依赖关系前置,CMD是按需加载。


AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。

CMD是SeaJS在推广过程中对模块定义的规范化产出

对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。

CMD:延迟执行(运行按需加载,根据顺序执行)
AMD:提前执行(异步加载:依赖先执行)+延迟执行

<span style="font-weight: normal;">// 所有模块都通过 define 来定义
define(function(require, exports, module) {

  // 通过 require 引入依赖
  var $ = require('jquery');
  var Spinning = require('./spinning');

  // 通过 exports 对外提供接口
  exports.doSomething = ...

  // 或者通过 module.exports 提供整个接口
  module.exports = ...

});</span>

SeaJS学习

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>seajs</title>
    </head>
    <body>
    <script type="text/javascript" src="sea.js"></script>
    <script type="text/javascript">
        seajs.use('dialog',function(Dialog){
            //alert(Util.add(1,2));
            //console.log([1,5,4,3,2].sort(Util.sorts));//[1, 2, 3, 4, 5]
            var res=Dialog.sum([1,5,4,3,2]);
            console.log(res);//15
        });
    </script>
    </body>
</html>

util,js

define(function(require,exports){
    exports.add=function(x,y){
        return x+y;
    };
    exports.sorts=function(num1,num2){
        if(num1>num2){
            return 1;
        }else if(num1<num2){
            return -1;
        }else{
            return 0;
        }
    };
});

dialog.js

define(function(require,exports){
    var util=require('./util.js');
    exports.sum=function(arr){
        var sum=0;
        console.log(arr.sort(util.sorts));
        for(var i=0;i<arr.length;i++){
            sum+=arr[i];
        }
        return sum;
    };
});

SeaJS对模块的态度是懒执行, 而RequireJS对模块的态度是预执行

SeaJS只会在真正需要使用(依赖)模块时才执行该模块
SeaJS是异步加载模块的没错, 但执行模块的顺序也是严格按照模块在代码中出现(require)的顺序.

而RequireJS会先尽早地执行(依赖)模块, 相当于所有的require都被提前了, 而且模块执行的顺序也不一定100%就是先mod1再mod2
因此你看到执行顺序和你预想的完全不一样!

CommonJS规范

CommonJS是服务器端模块的规范,Node.js采用了这个规范。Node.JS首先采用了js模块化的概念。

根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。

加载模块使用 require方法,该方法读取一个文件并执行,最后返回文件内部的 module.exports对象。


待续。。。。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值