Javascript模块化编程

Javascript模块化编程

  • 原始写法
function m1(){
}

function m2(){

}

模块就是实现特定功能的一组方法。只要把不同的函数简单的放在一起,就算是一个模块。这种做法的缺点就是,污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。

  • 在原始写法上进行改进,原始写法变为对象写法
var module = new Object({
    _count:0,
    m1:function(){
        console.log("执行m1函数");
    },
    m2:function(){
        console.log("执行m2函数");
    }
});

所以调用m1或者m2的时候直接调用对象的属性。但这样的写法会暴露所有模块成员,内部状态可以被外部改写。

  • 在对象写法上进行改进,使用立即执行函数写法

使用立即执行函数,可以达到不暴露私有成员的目的

var module=(function(){
    var _count=0;
    var m1 = function(){
        console.log("执行m1函数");
    };
    var m2 = function(){
        console.log("执行m2函数");
    };

    return {
        m1:m1,
        m2:m2
    };
})();
  • 放大模式

如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用放大模式

var module = (function(mod){
    mod.m3 = function(){
        console.log("添加了模块方法3");
    };

    return mod;
})(module);
  • 宽放大模式

在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用放大模式,有可能加载一个不存在空对象,这时就要采用宽放大模式

var module = (function(mod){
    //.....
    return mod;
})(window.module||{});
  • 输入全局变量,模块内部用全局变量的别名
var module = (function($){
    //....
})(jQuery);

模块的规范

因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,就完全乱了。目前通行的Javascript模块规范共有两种:CommonJS与AMD。

//require是一个全局加载模块函数
var math = require('math');
math.add(2,3);//5

这在浏览器端就碰到一个巨大的问题,要执行math.add(2,3) 就必须等math.js加载完成,也就是说,如果加载时间很长,整个应用就会停在那里等,浏览器会出现假死。但是服务器端的node.js是可以同步加载的,所以浏览器端只能用异步加载。所以AMD就出现了Asynchronous Module Definition,它采用异步方式加载模块,模块的加载不影响它后面语句的运行,所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

AMD 也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数reuire([module],callback),第一个参数[module]是一个数组,里面的成员就是要加载的模块,第二个参数callback,则是加载成功之后的回调函数。

require(['math'],function(math){
    math.add(2,3);
});

为什么需要require.js

最早的时候,所有JavaScript代码都写在一个文件里面,只要加载这个文件就够了。后来代码越来越多,一个文件不够了,就必须分成多个文件,依次加载,如下面的模式

<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
<script src="4.js"></script>

这段代码依次加载多个js文件,这样的写法有很大的缺点。缺点一:加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;缺点二:由于js文件之间存在依赖关系,因此必须严格保证加载顺序,比如2.js依赖于1.js那么1.js必须放在2.js前面,依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会越来越难维护了。

require.js的出现就是解决:1,实现js文件的异步加载,避免网页失去响应;2,管理模块之间的依赖性,便于代码的编写和维护。

require.js的写法

//require.js加载

//普通常用写法
<script src="js/require.js"></script>
<script src="js/business.js"></script>

//异步加载写法,避免阻塞网页Dom渲染,IE支持`defer`,其他浏览器支持 `async="true"`
<script src="js/require.js" defer async="true" data-main="js/business.js"></script>
  • 业务模块写法

下面说说main.js的写法

//main.js
require(['moduleA','moduleB','moduleC'],function(moduleA,moduleB,moduleC){
    //main.js中的业务代码
});

//真实中
require(['jquery','underscore','backbone'],function($,_,Backbone){
    //main.js中的业务代码
});
  • 模块名与模块路径定义

看到上面的写法,我们发现jquery,underscore,backbone 这些是从哪里来的,我们知道require.js就是解决异步加载与模块依赖问题,想到了估计跟定义模块名称模块的js文件路径有关,下面就给出如何定义模块。

//直接单独定义路径,路径默认的文件后缀名为`.js`,所以`jquery.min.js` 可以写成 `jquery.min`
//这是相对路径写法,相对于main.js文件的路径
require.config({
    paths:{
        "jquery":"jquery.min",
        "underscore":"underscore.min",
        "backbone":"backbone.min"   
    }
});
//绝对路径写法
require.config({
    paths:{
        "jquery":"/js/lib/jquery.min",
        "underscore":"/js/lib/underscore.min",
        "backbone":"/js/lib/backbone.min"   
    }
});
//基目录写法
require.config({
    baseUrl:"/js/lib",
    paths:{
        "jquery":"jquery.min",
        "underscore":"underscore.min",
        "backbone":"backbone.min"   
    }
});
  • 功能模块写法
//math功能模块,math.js,不依赖于其他模块的情况写法
define(funciton(){
    var add = function(x,y){
        return x+y;
    };
    return{
        add:add
    };
});

//依赖于`commonLib`模块的写法
define(['commonLib'],function(commonLib){
    function isTelphoneNumber(phoneNumber){
        var isPhoneNumber=commonLib.checkPhoneNumber(phoneNumber);
        return isPhoneNumber;
    }
    return {
        isTelPhoneNumber:isTelphoneNumber
    };
});
  • 加载非规范的模块

理论上,require.js加载的模块,必须是按照AMD规范、用define()函数定义的模块。但是实际上,虽然已经有一部分流行的函数库(比如jQuery)符合AMD规范,更多的库并不符合规范。鉴于那种情况,require.js还是支持非规范的模块。

这样的模块在用require()加载前,要先用require.config()方法,定义它们的一些特征。

//比如 underscore与backbone这两个库,都没有采用AMD规范编写。如果需要加载他们的话,就必须定义它们的特征。
require.cnfig({
    shim:{
        'underscore':{
            exports:'_'
        },
        'backbone':{
            deps:['underscore','jquery'],
            exports:'backbone'
        }
    }
});

属性shim 专门用来配置不兼容的模块。1:每个模块的exports值的输出变量名,表明这个模块外部调用时的名称;2:deps数组,表明该模块的依赖性。

  • require.js插件

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文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值