SeaJS基本开发原则

SeaJS基本开发原则
在讨论SeaJS的具体使用前,先介绍一下SeaJS的模块化理念和开发原则。
使用SeaJS开发JavaScript的基本原则就是:一切皆为模块。引入SeaJS后,编写JavaScript代码就变成了编写一个又一个模块,SeaJS中模块的概念有点类似于面向对象中的类——模块可以拥有数据和方法,数据和方法可以定义为公共或私有,公共数据和方法可以供别的模块调用。
另外,每个模块应该都定义在一个单独js文件中,即一个对应一个模块。
下面介绍模块的编写和调用。
模块的定义及编写
模块定义函数define
SeaJS中使用“define”函数定义一个模块。因为SeaJS的文档并没有关于define的完整参考,所以我阅读了SeaJS源代码,发现define可以接收三个参数:

复制代码代码如下:
/**
* Defines a module.
* @param {string=} id The module id.
* @param {Array.|string=} deps The module dependencies.
* @param {function()|Object} factory The module factory function.
*/
fn.define = function(id, deps, factory) {
    //code of function…
}

上面是我从SeaJS源码中摘录出来的,define可以接收的参数分别是模块ID,依赖模块数组及工厂函数。我阅读源代码后发现define对于不同参数个数的解析规则如下:
s
如果有两个参数,第二个赋值给factory;第一个如果是array则赋值给deps,否则赋值给id。
如果有三个参数,则分别赋值给id,deps和factory。
但是,包括SeaJS的官方示例在内几乎所有用到define的地方都只传递一个工厂函数进去,类似与如下代码:

复制代码代码如下:

define(function(require, exports, module) {
    //code of the module...
});

个人建议遵循SeaJS官方示例的标准,用一个参数的define定义模块。那么id和deps会怎么处理呢?
id是一个模块的标识字符串,define只有一个参数时,id会被默认赋值为此js文件的绝对路径。如example.com下的a.js文件中使用define定义模块,则这个模块的ID会赋值为 http://example.com/a.js ,没有特别的必要建议不要传入id。deps一般也不需要传入,需要用到的模块用require加载即可。
工厂函数factory解析
工厂函数是模块的主体和重点。在只传递一个参数给define时(推荐写法),这个参数就是工厂函数,此时工厂函数的三个参数分别是:
1.require——模块加载函数,用于记载依赖模块。
2.exports——接口点,将数据或方法定义在其上则将其暴露给外部调用。
3.module——模块的元数据。
这三个参数可以根据需要选择是否需要显示指定。
下面说一下module。module是一个对象,存储了模块的元信息,具体如下:
1.module.id——模块的ID。
2.module.dependencies——一个数组,存储了此模块依赖的所有模块的ID列表。
3.module.exports——与exports指向同一个对象。
三种编写模块的模式
第一种定义模块的模式是基于exports的模式:

复制代码代码如下:

define(function(require, exports, module) {
    var a = require(‘a‘); //引入a模块
    var b = require(‘b‘); //引入b模块

var data1 = 1; //私有数据

var func1 = function() { //私有方法
        return a.run(data1);
    }

exports.data2 = 2; //公共数据

exports.func2 = function() { //公共方法
        return ‘hello‘;
    }
});

上面是一种比较“正宗”的模块定义模式。除了将公共数据和方法附加在exports上,也可以直接返回一个对象表示模块,如下面的代码与上面的代码功能相同:

复制代码代码如下:
define(function(require) {
    var a = require(‘a‘); //引入a模块
    var b = require(‘b‘); //引入b模块

var data1 = 1; //私有数据

var func1 = function() { //私有方法
        return a.run(data1);
    }

return {
        data2: 2,
        func2: function() {
            return ‘hello‘;
        }
    };
});

如果模块定义没有其它代码,只返回一个对象,还可以有如下简化写法:

复制代码代码如下:
define({
    data: 1,
    func: function() {
        return ‘hello‘;
    }
});

第三种方法对于定义纯JSON数据的模块非常合适。
模块的载入和引用
模块的寻址算法
上文说过一个模块对应一个js文件,而载入模块时一般都是提供一个字符串参数告诉载入函数需要的模块,所以就需要有一套从字符串标识到实际模块所在文件路径的解析算法。SeaJS支持如下标识:
绝对地址——给出js文件的绝对路径。
如:

复制代码代码如下:
require("http://example/js/a");

就代表载入 http://example/js/a.js 。
相对地址——用相对调用载入函数所在js文件的相对地址寻找模块。
例如在 http://example/js/b.js 中载入
复制代码代码如下:
require("./c");

则载入 http://example/js/c.js 。
基址地址——如果载入字符串标识既不是绝对路径也不是以”./”开头,则相对SeaJS全局配置中的“base”来寻址,这种方法稍后讨论。
注意上面在载入模块时都不用传递后缀名“.js”,SeaJS会自动添加“.js”。但是下面三种情况下不会添加:
载入css时,如:
复制代码代码如下:
require("./module1-style.css");

路径中含有”?”时,如:
复制代码代码如下:
require(<a href="http://example/js/a.json?cb=func">http://example/js/a.json?cb=func</a>);

路径以”#”结尾时,如:
复制代码代码如下:
require("http://example/js/a.json#");

根据应用场景的不同,SeaJS提供了三个载入模块的API,分别是seajs.use,require和require.async,下面分别介绍。
seajs.use
seajs.use主要用于载入入口模块。入口模块相当于C程序的main函数,同时也是整个模块依赖树的根。上面在TinyApp小例子中,init就是入口模块。seajs.use用法如下:

复制代码代码如下:

//单一模式
seajs.use(‘./a‘);

//回调模式
seajs.use(‘./a‘, function(a) {
  a.run();
});

//多模块模式
seajs.use([‘./a‘, ‘./b‘], function(a, b) {
  a.run();
  b.run();
});

require
require是SeaJS主要的模块加载方法,当在一个模块中需要用到其它模块时一般用require加载:

复制代码代码如下:
var m = require(‘/path/to/module/file‘);

这里简要介绍一下SeaJS的自动加载机制。上文说过,使用SeaJS后html只要包含sea.js即可,那么其它js文件是如何加载进来的呢?SeaJS会首先下载入口模块,然后顺着入口模块使用正则表达式匹配代码中所有的require,再根据require中的文件路径标识下载相应的js文件,对下载来的js文件再迭代进行类似操作。整个过程类似图的遍历操作(因为可能存在交叉循环依赖所以整个依赖数据结构是一个图而不是树)。
明白了上面这一点,下面的规则就很好理解了:
传给require的路径标识必须是字符串字面量,不能是表达式,如下面使用require的方法是错误的:
复制代码代码如下:
require(‘module‘ + ‘1‘);
require(‘Module‘.toLowerCase());

这都会造成SeaJS无法进行正确的正则匹配以下载相应的js文件。
require.async
上文说过SeaJS会在html页面打开时通过静态分析一次性记载所有需要的js文件,如果想要某个js文件在用到时才下载,可以使用require.async:

复制代码代码如下:
require.async(‘/path/to/module/file‘, function(m) {
    //code of callback...
});

这样只有在用到这个模块时,对应的js文件才会被下载,也就实现了JavaScript代码的按需加载。
SeaJS的全局配置
SeaJS提供了一个seajs.config方法可以设置全局配置,接收一个表示全局配置的配置对象。具体使用方法如下:

复制代码代码如下:
seajs.config({
    base: ‘path/to/jslib/‘,
    alias: {
      ‘app‘: ‘path/to/app/‘
    },
    charset: ‘utf-8‘,
    timeout: 20000,
    debug: false
});

其中base表示基址寻址时的基址路径。例如base设置为 http://example.com/js/3-party/ ,则:
复制代码代码如下:
var $ = require(‘jquery‘);

会载入 http://example.com/js/3-party/jquery.js 。
alias可以对较长的常用路径设置缩写。
charset表示下载js时script标签的charset属性。
timeout表示下载文件的最大时长,以毫秒为单位。
debug表示是否工作在调试模式下。

SeaJS如何与现有JS库配合使用
要将现有JS库如jQuery与SeaJS一起使用,只需根据SeaJS的的模块定义规则对现有库进行一个封装。例如,下面是对jQuery的封装方法:

复制代码代码如下:
define(function() {

//{{{jQuery原有代码开始
/*! 
* jQuery JavaScript Library v1.6.1
http://jquery.com/
*
* Copyright 2011, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
http://jquery.org/license
*
* Includes Sizzle.js
http://sizzlejs.com/
* Copyright 2011, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Thu May 12 15:04:36 2011 -0400
*/
//...
//}}}jQuery原有代码结束

return $.noConflict();
});

时间: 2024-12-27 21:47:02

SeaJS基本开发原则的相关文章

初学seaJs模块化开发,利用grunt打包,减少http请求

原文地址:初学seaJs模块化开发,利用grunt打包,减少http请求 未压缩合并的演示地址:demo2 学习seaJs的模块化开发,适合对seajs基础有所了解的同学看,目录结构 js — —dist   //压缩后的目标文件夹 —lib   //各个模块 —drag    //拖拽模块 —scale   //缩放模块 —seajs    //seajs库 —seajs_drag    //入口的主文件main.js —main.js /*——————————————————————————

敏捷软件开发:原则、模式与实践(笔记)

一.敏捷软件开发宣言 1.个体和交互 > 过程与工具 a)人是获得成功最为重要的因素: b)合作.沟通以及交互能力要比单纯的编程能力更为重要: c)团队的构建要比环境的构建重要. 2.可以工作的软件 > 面面俱到的文档 a)文档应该短小并突出主题: b)在给新的团队成员传授知识方面,最好的两份文档是代码和团队: c)直到迫切需要并且意义重大时,才来编制文档. 3.客户合作 > 合同谈判 a)成功的项目需要有序.频繁的客户反馈. 4.响应变化 > 遵循计划 a)构建计划时,应该确保计

一个开发原则,永远不要返回NULL

看一篇文章:10个经典的java开发原则,里面一个原则:永远不要返回NULL. 为什么,因为很多代码都是 a.b(......).c(...) 这么连着调用.如果每层调用都要检查是否为空的话,代码就太难看了. 但是不返回null,返回什么呢?显然要反悔一个类的实例,但是怎么保证得到的结果是预期的呢,也就是说,怎么能保证这样虽然不会报“未交对象引用设置到对象的实例”(实际上就是空引用)这个错误,但是能得到“正确”的结果呢.显然,应该是nul但是没有返回null是得不到正确的结果,但是我们要保证结果

程序员需谨记的8条团队开发原则(转)

当你从学校出来,找到第一份软件开发工作的时候,你就不再是一个单独作战的程序员了,你将会有一个团队,你的一举一动也将直接影响团队的效率和产出.下面这8条团队开发的基本原则,作为团队的一员,你必须谨记在心,这会对你和你的团队带来非同凡响的效果. 1.提交(签入)代码需要填写备注说明 团队开发中必定会使用一些类似svn的代码管理工具,在提交代码时填写备注,这个好处是不言而喻的.它可以帮你记录这次修改完成了哪些功能.修复了哪些bug,包括的团队的其他成员,也可以看到你这次提交代码所做的贡献. 2.每天汇

敏捷开发-原则 模式与实践(1)

敏捷开发-原则 模式与实践 这的确是一本关于开发者的好书,对于我们开发者.研究人员,它提出了一个开发的全新的价值观(对我来说),甚至人生都有启发.需要认真阅读. 书中总结了敏捷开发的实例,确确实实更够感觉到对于项目的完成大有裨益,有种相读恨晚的感觉.想想自己之前的开发状态,想想自己导师安排公司项目的情况,就是低效率,就是小儿科,就是书上批评讽刺的那样,这正是开发者十几年开发智慧的结晶,前人的经验,前人的智慧,激发了我的阅读的快感,我获取知识的兴奋感,激发了我的成就感. 阅读前两天(结合思维导图)

敏捷软件开发原则

敏捷软件开发原则 ----<敏捷软件开发原则.模式与实践>学习笔记 最近在系统地学习并且有意地在工作中实践敏捷软件开发,文章乍看起来,都是一些说教性.理论性,比较无聊的东西. 但是如果静下心来结合自己自身的经历.思考地去阅读,可能会发现,有的观点确实很赞同,然而有的可能会有自己的想法. 以下是在<敏捷软件开发 原则.模式与实践>一些读书笔记,斜体字是直接摘录于书本,非斜体字是自己的一些理解.   一.尽早的,持续地交互有价值的软件来使客户满意.初期交付的系统功能越少,最终交付的系统

3 条重要的软件开发原则

英文原文:3 Key Software Principles You Must Understand,翻译:iteye 在本文中将介绍 3 条重要的软件开发原则(DRY.KISS.YAGNI原则),你可能已经知道,也可能只知道其中一条.这些原则看似很简单,但实施起来会很难.无论如何,这些原则提供了一个管理复杂软件项目的强大的途径.当涉及到真实世界中的项目开发时,你会发现这些原则都是非常有用的. 原则1:不要重复自己(Don’t Repeat Yourself,DRY 原则) 这个原则非常重要,换

3 条你必须知道的软件开发原则

在本文中将介绍3条重要的软件开发原则,你可能已经知道,也可能只知道其中一条.这些原则看似很简单,但实施起来会很难.无论如何,这些原则提供了一个管理复杂软件项目的强大的途径.当涉及到真实世界中的项目开发时,你会发现这些原则都是非常有用的. 原则1:不要重复自己(Don’t Repeat Yourself,DRY原则) 这个原则非常重要,换言之,就是不要写重复的代码. 当你正在构建一个大型的软件项目时,你通常会被整体复杂性搞得不知所措.解决复杂性的最基本的策略是将系统分成若干个容易处理的部分.起初,

【转】程序员需谨记的8条团队开发原则

当你从学校出来,找到第一份软件开发工作的时候,你就不再是一个单独作战的程序员了,你将会有一个团队,你的一举一动也将直接影响团队的效率和产出.下面这8条团队开发的基本原则,作为团队的一员,你必须谨记在心,这会对你和你的团队带来非同凡响的效果. 1.提交(签入)代码需要填写备注说明 团队开发中必定会使用一些类似svn的代码管理工具,在提交代码时填写备注,这个好处是不言而喻的.它可以帮你记录这次修改完成了哪些功能.修复了哪些bug,包括的团队的其他成员,也可以看到你这次提交代码所做的贡献. 2.每天汇