Seajs模块化开发Javascript - 用代码说话(一)

  前言javascript

    模块化开发JS已经逐渐开始普及,在RequireJS和SeaJS中犹豫了2天,最后选择从SeaJS入手.网上有很多教程和使用方法,不过理论东西太多了,我是标准的实用主义和拿来主义者,因此直接用代码说话.
html

  正文前端

    先上一个最简单的Demo,比官网上的简单无数倍:
java

    从官网下载最新版本的Sea.js文件,我下载的是2014年3月19的2.2.1版:https://github.com/seajs/seajs/archive/2.2.1.zip.git

    咱们就须要dist中的sea.js便可,接下来在dist文件夹同目录下建立demo.html,util.js,componet_one.js这三个文件.
github

    util.js文件中定义一个功能,单独做为一个模块:
前端工程师

//util.js
define(function (require,exports,module) {  
    function print (str) {    
    // body...    
    alert(str);  
    }  
    exports.print = print;
});

    而后定义componet_one.js,它的实现依赖于util.js:异步

//componet_one.js
define(function (require,exports,module) {  
    var util = require("./util.js");  
    var ComponetOne = {    
        doSth : function(){      
        util.print("I'm a String.")    
        }  
    }  
    return ComponetOne;
})

    最后在index.html页面上,直接开始调用:async

<!doctype html>
<html>
    <head>
      <meta charset="UTF-8">
    <title>SeaJS</title>
    </head>
    <body>
      <script type="text/javascript" src="dist/sea.js"></script>
        <script type="text/javascript">
            seajs.use("./componet_one.js",function(componet_one){
                  componet_one.doSth();
            });  
        </script>
    </body>
</html>

    页面上显示的结果是弹出一个对话框上面写着:模块化

"I'm a String."

    示例完毕,感受如何,我认为即便对模块化或者Sea.js和RequireJS一点概念都没有,只要有必定的Javascript基础都能理解或者说猜出上面代码的功能和内容.做为理解模块化的入门以及Sea.js应该算是最简单的代码了.

    代码虽少,不过仍是能够很直观的看出一些东西的,因此经过这几段简单代码来引入一些Sea.js中的API和使用方法.由于Sea.js遵循的是CommonJS规范,因此它的API使用起来虽然看着和RequireJS很像,但仍是有所不一样,而且它们内部实现也不同.

    

    (1) CMD模块定义规范

    在上面的util.js中经过define()定义了一个模块,能够看到全局函数define就接受了一个函数参数.其实define还可接受对象或者字符串为参数,这时表示模块的接口就是这对象、字符串.

define({"foo" : "bar});
define("It's a template");

    这都是能够的,大多数的状况下仍是以函数为参数,表示模块的构造方法.执行这个构造方法能够获得模块向外提供的接口,好比上面utils.js中就是如此.这种状况下方法执行时,默认传入三个参数:require、exports以及module.

    若是你不知道是否能够在当前开发项目中使用define,能够经过define.cmd进行判断当前页面是否有CMD模块加载器:

if (typeof define === "function" && define.cmd){    
    //此时表示存在Sea.js等CMD模块加载器
}

  

    (2) 经过exports对象向外提供模块接口

    在util.js中define定义的方法体内,有一行代码是exports.print = print;什么都不看的解释是将方法体内定义的print函数指向exports的print属性.

    exports是define()定义模块时,Function传入的三个默认参数之一,经过它能够对外提供属性或者方法.

    除了给exports对象增长成员,也能够经过return直接向外提供接口,将util.js改成return的方式就以下:

define(function (require,exports,module) {  
    return {   
        print : function(str) {
              // body...      
              alert(str);    
        }
     }
});

    还能够经过module.exports进行赋值,module是define()的参数为函数参数时的函数参数的一个函数.这么说有点费劲,那么我对以前说的define进行一点补充.

    标准说法的define,应该是define(factory)做为define的参数,factory可使一个函数,也能够是一个对象或者字符串.因此说require、exports和module都是factory的默认参数.

    util.js经过module.exports的写法以下,效果是同样的:

define(function (require,exports,module) {  
    module.exports =  {   
        print : function(str) {
              // body...
              alert(str);
        }
     }
});

    exports仅仅是module.exports的一个引用,在factory内部给exports从新赋值时,不会改变module.exports的值,所以给exports赋值是没有效果的,不能用来改变模块接口.这个地方exports和module.exports的关系和Nodejs中是彻底同样的.


    (3) 存储当前模块属性和方法的module

     既然上面以及提到了module,这里就接着往下说,module中最有意义也是须要掌握的就是module.exports,这个在上面说exports的时候提到了.传给factory构造方法的exports参数是module.exports对象的一个引用.仅仅经过exports参数提供接口有时没法知足需求.

    例如当模块的接口是某个类的实例时,就要经过module.exports来实现:

define(function (require,exports,module) {    
    //exports 是 module.exports 的一个引用  
    console.log(module.exports === exports);  //true
    module.exports = new SomeClass();  
    console.log(module.exports === exports);  //false
});

    

    (4) 经过require获取模块

    经过define、exports以及module的介绍相信util.js中的代码是什么意思并不难理解,而后看一下componet_one.js文件,它也是一个经过define定义的模块,在factory中第一行:var util = require("./util.js");

    若是以前用过Nodejs,那么对于require就很熟悉了.它经过一个模块标识做为惟一参数,用来获取模块提供的接口.这里就是获取到了util模块,可使用util.js文件中定义的内容,这点没什么疑问.

    require还有一个实现就是require.async方法用来在模块内部异步加载模块,并在加载完成后执行回调函数.

define(function(require,exports,module){    
    //异步加载一个模块,加载完成后执行callback  
    require.async('./b',function(b){
        b.dosth();
    });
    //异步加载多个模块,而后执行callback
    require.async(['./c','./d'],function(c,d){
        c.dosth();
        d.dosth();
    });
});

    结尾

        相似RequireJS和SeaJS这类模块加载器,它们的实质是为了弥补Javascript在设计之处的不足,能够想象就连Javascript的发明者也没有预料到今天Javascript的火热和普及程度,因此在设计上没有作好文件组织管理这方面的功能.

    由于早期它看起来确实就是一种简单的脚本语言,一个页面也就一个JS文件直接引入就行了.可是随着Javascript火爆的发展以及大量的应用,这明显成为其短板,因此广大优秀的Coder们想出了各类办法进行解决.

    模块加载主要目的是令JavaScript开发模块化并能够轻松愉悦进行加载,将前端工程师从繁重的JavaScript文件及对象依赖处理中解放出来,能够专一于代码自己的逻辑.

        后续会逐渐写一些更实用的东西,欢迎留言给我,一块儿学习~

相关文章
相关标签/搜索