seajs学习笔记

      现在公司开发的项目大量用到了JS,由于项目模块要求不同,编程人员的开发水平也不同,前端的JS写的非常的乱,最近一段时间也在思索着如何才能以最小的成本,在不大幅提高编程难度的前提下最大化的规范前端编程.前几天看了一篇文章:使用SeaJS实现模块化JavaScript开发,然后又仔细研究了关天,感觉很不错,现将研究心得分享如下.

      一.模块化

      JS的模块化编程思路其实来源于一系列编程规范(如CommonJS)和此规范的一些实现(如Nodejs),虽然我对以上提到的这些东东没有什以研究,但是以我在改别人前端代码的痛苦经历和就"模块化"这三个字的字面意思来讲,还是能够理解它想表达的意思.所谓"模块化",就是以分治法为依据,把一个大的问题分解成若干个高内聚,低耦合的小的问题.最后通过一系列依赖关系明确的相互调用,最后共同解决那个大问题.这里的两个关键是高内聚与明确的低的耦合.seajs解决的正是后面一个关键.

      二.seajs概述

      大部分情况下,引入一个新的内容都会增加旧有内容的复杂性.既然它的目标是降低复杂性,那么它本身就应该保持足够的简单.seajs非常好的遵守了KISS原则.SeaJS仅向全局公开了两个标识符:seajs与define.

      seajs对象有两个方法use和config.下面是define方法的结构图

     

      可以看到,define的第一个参数与module的属性都有一个叫id的.其实他们是一回事,如果传入id,module则用它,如果不传入,则使用一个默认的规则生成每个模块的id.

      define的第二个参数dependencies与module的属性dependencies也是有关系的.module的属性dependencies是传入的dependencies集合并上使用require方法获取的依赖的集合.

      define是个重要的方法,它有三个参数:require,exports与module.这个方法的构造完全附合CommonJS下面的Modules/Wrappings规范:使用require获取“依赖”,使用exports导出“接口”,而module则代表被定义的模块本身.

      seajs对象与define方法的具体使用方法可以参考官方的文档进行学习.从一般使用顺序来讲,首先通过seajs.config进行全局配置,然后通过define定义各个模块,最后通过seajs.use方法使用各模块.如果能按照这个方法去理解,应该就能够很快的掌握这个框架.

      下面来谈谈我对使用seajs框架的理解

      一.代码组织

      如果一个网站的JS全部是由seajs组织的,你就会发现所有的js只会出现在两个地方:define里与seajs.use里.在define里,因为这里是模块定义的位置;在seajs.use里,因为这里是唯一能够使用由define定义的模块的地方.通过define定义模块,所有的功能都被封装成一个个js对象,且这些对象是闭包的,只有通过seajs.use方法的第二个参数----一个回调函数的参数才能使用这些定义的对象.

      二.顺序加载

      由于seajs仅仅是一个模块加载器而不是文件加载器,它不能保证脚本一定是按代码的书写顺序进行加载.为了应付这种情况,seajs推荐使用LABjs配合seajs进行使用.

      Labjs的使用也比较简单,使用script方法加载脚本,使用wait方法执行脚本.更加具体的说明请参照其官方文档.

      三.循环引用

      参见下面三段代码:

//a.js
define(function(require, exports, module) {
    var b = require("b");
    alert(b);
    return b + 1;
})
//b.js
define(function(require, exports, module) {
    var a = require("a");
    alert(a);
    return a + 2;
})
//html
seajs.use(["a.js"], function(result) {
    alert(result);
})

      请问发现了什么问题.答案是a模块与b模块发生了循环引用.这个问题如果在seajs早期的版本里,貌似会报异常,但是现在不会了.当html页面请求a模块时,a模块发现其依赖于b模块,于是执行b模块.但是此时发现其又依赖a模块.seajs现在的处理是直接返回一个空对象{},所以先是弹出[object Object],然后弹出[object Object]2,最后弹出[object Object]21.

      四.脚本改写

      现有其它类库是不能直接被seajs引用的,而是需要根据SeaJS的的模块定义规则对现有库进行一个封装.以官方封装的jquery1.7.1为例:

(function(factory) {

  if (typeof define === 'function') {
    define('#jquery/1.7.1/jquery', [], factory);
  }
  else {
    factory();
  }

})(function(require) {
  //jquery原生代码
  if (require) return $.noConflict(true);
});

      它的封装规则,就是在jquery原生代码的上下加上特定代码.可以看到当typeof define == 'function',则说明当前js环境为seajs环境,使用define方法进行封装,否则直接调用传入的factory匿名函数.

      对于匿名函数,如果是seajs环境,则传入的require变量不为空,则就回调用jquery的noConflict方法.该方法可以让你自定义jquery的控制变量.

      这样封装的好处理,如果没有seajs环境,则可以像普通写法一样在script标签引入脚本,如果是seajs环境,则通过seajs引入.同一个脚本满足了两个执行环境.

      五.调试模式

      seajs还提供了一个官方插件plugin-map.js,它提供了seajs的在线本地调试模式.当你把它放在seajs的同级目录下,然后在URL后面加上?seajs-debug参数时,窗口的右下脚就会出现一个输入框让你输入需要调试的脚本的路径.点击刷新后,网站脚本的来源就变成你设定的来源了.

      以上就是我研究seajs的心得.在研究的过程中参考了作者的官方参考与园友的研究成果,在这里一并感谢了.也祝愿玉伯这个少有的得到众多认可的国产框架写的越来越好:)

 

      参考的文章

      1.从 RequireJS 到 SeaJS (1), (2), (3), (4), (5) (可能需要FQ)

      2.在线本地调试大观 (可能需要FQ)

      3.jQuery 插件的模块化 (可能需要FQ)

      4.seajs官方

      5.拥抱模块化的JavaScript

      6.什么是CommonJS

      7.使用SeaJS实现模块化JavaScript开发

      8.SeaJS快速入门,让js代码模块化 - 2011-09-09修订,新增参考资料

      9.JavaScript模块化开发库之SeaJS

      10.seajs – 全局map,调试利器

      11.对之前分享到微博demo的一些改进

      12.关于seajs模块间相互依赖调用的解耦问题

      13.Javascript文件加载:LABjs和RequireJS

      14.labJS 介绍

      15.LABjs

      16.我的模块加载系统 v3

      17.工程化前端开发

      18.js模块化开发---js大项目代码组织和多人协作的解决之道

      19.通用前端开发框架(一)

posted @ 2012-05-08 23:00  永远的阿哲  阅读(3776)  评论(3编辑  收藏  举报