- 浏览: 1172446 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
zhizhen23:
LZ 提供的链接地址失效了
重写的isPlainObject方法 -
LovingBaby:
LovingBaby 写道function fun() {}f ...
读jq之二(两种扩展) -
LovingBaby:
说的很清楚!jQuery作者为了实现简洁调用的苦心!高超的编程 ...
读jq之一(jq对象的组成) -
hard_ly:
...
将伪数组转换成数组 -
zlxzlxzlxzlxzlx:
这不能算是任意进制之间的转换,例如二十六进制、十二进制又该如何 ...
用递归实现十进制数转换N进制
JavaScript模块化开发库之SeaJS
- 博客分类:
- Modular JS
SeaJS由国内的牛人lifesinger开发。目前版本是1.1.1,源码不到1500行,压缩后才4k,质量极高。
这篇会讲述SeaJS的一些基本用法,不会面面俱到,但会就个人的理解讲述官方文档没有提到的一些细节。
一、SeaJS的全局接口
SeaJS向全局公开了两个标识符: seajs 和 define。
如果你的项目中已经用了标识符seajs,又不想改。这时SeaJS可以让出全局的seajs。如
var boot = seajs.noConflict();
这时boot就相当于先前的seajs。
如果你的项目中连标识符define也用到了,也不想改。SeaJS是很宽容的,它的define也可以让出。如
var boot = seajs.noConflict(true);
较上面仅多传了一个true。这时全局的define也没了。这时需要用boot.define来代替之前的define。
用过jQuery的同学应该很熟悉$.noConflict方法,SeaJS的noConflict与之类似。
二、SeaJS的模块写法
SeaJS默认使用全局的define函数写模块(可把define当成语法关键字),define定义了三个形参id, deps, factory。
define(id?, deps?, factory);
这个define很容易让你想起AMD的唯一API:define函数。 或者说让人费解,导致搞不懂SeaJS和 RequireJS define的区别。
它们都有个全局的define,形参都是三个,且对应的形参名也一样,会误认为SeaJS也是AMD的实现。
事实上SeaJS和RequireJS的define前两个参数的确一样。
id都为字符串,都遵循 Module Identifiers。deps都是指依赖模块,类型都为数组。区别仅在于第三个参数factory,虽然类型也都是函数,但其参数意义却不同。
RequireJS中factory的参数有两种情况
a、和deps(数组)元素一一对应。即deps有几个,factory的实参就有几个。
define(['a', 'b'], function(a, b){ // todo });
b、固定为require,exports, module(modules/wrappings格式)。
define(function(require, exports, module){ // todo });
这种方式是RequireJS后期向 Modules/Wrappings 的妥协,即兼容了它。而SeaJS的define仅支持RequireJS的第二种写法:Modules/Wrappings。
注意:SeaJS遵循的是 Modules/Wrappings 和 Modules/1.1.1。这两个规范中都没有提到define关键字,Modules/Wrapping中定义模块要求使用的是module.declare而非define。而恰恰只有AMD规范中有define的定义。即虽然SeaJS不是AMD的实现,但它却采用了让人极容易误解的标识符define。
说了这么多,还没开始写一个模块。下面我们从最简单的开始
1、简单模块
define({ addEvent: function(el, type, fn){}, removeEvent: function(el, type, fn){}, fireEvent: function(el, type){} });
这样就写了一个事件模块,这和写一个单例没有区别。更多的时候用该方式定义纯数据模块。它类似于
var E = { addEvent: function(el, type, fn){}, removeEvent: function(el, type, fn){}, fireEvent: function(el, type){} };
2、简单的包装模块
define(function() { // 一些内部辅助函数 // ... function addEvent() { // .. } function removeEvent() { // .. } function fireEvent() { // .. } return { addEvent: addEvent, removeEvent: removeEvent, fireEvent: fireEvent }; });
您懂的,在这个匿名函数中可以做很多事情。最后只需公开必要的接口。它类似于
var E = function() { // 一些内部辅助函数 // ... function addEvent() { // .. } function removeEvent() { // .. } function fireEvent() { // .. } return { addEvent: addEvent, removeEvent: removeEvent, fireEvent: fireEvent }; }();
3、NodeJS风格的包装模块
上面两种写法看不到一丝NodeJS风格(Modules/1.1.1),改写下与“方式2”等价的。
define(function(require, exports) { // 一些内部辅助函数 // ... function addEvent() { // .. } function removeEvent() { // .. } function fireEvent() { // .. } // 使用exports导出模块接口,而非返回一个对象 exports.addEvent = addEvent; exports.addEvent = removeEvent; exports.addEvent = fireEvent; });
可以看到与“方式2”区别在于:匿名函数有两个参数require、exports。这里导出接口不是return一个对象而是使用exports。而exports不正是NodeJS的风格吗? 细心的同学可能发现这个示例中require参数没有用到,这正是下面要讲的。
4、有依赖的模块
SeaJS中“依赖”都需要使用require函数去获取,虽然SeaJS的define的第二个参数deps也有“依赖”的意思,但它是提供打包工具(SPM)用的。此外,SeaJS的require是作为参数传入匿名函数内的,RequireJS的require则是全局变量。
上面定义的是一个没有依赖的模块,以下是有依赖的模块。
define(function(require, exports) { var cache = require('cache'); // ... exports.bind = bind; exports.unbind = unbind; exports.trigger = trigger; });
该事件模块依赖于cache模块,函数有两个形参require和exports。抛开外层的匿名函数及define,它就是标准的NodeJS格式:使用require函数取依赖模块,使用exports导出现有模块接口。
实际上在SeaJS中具有依赖的模块必须按“方式4”写,即必须是包装模块,且匿名函数的第一个参数必须是标识符 “require”。即可以把require当初语法关键字来使用,虽然它不是全局的。
下面我们看看匿名函数的参数require和exports的一些有趣现象
a、如果写的不是require,改成req会是什么结果。
define(function(req, exports) { var cache = req('cache'); // ... exports.bind = bind; exports.unbind = unbind; exports.trigger = trigger; });
Firebug网络请求如下
会看到依赖的“cache”没有被加载,当然JS肯定会报错了。
b、只把匿名函数的形参改成req,函数内部仍然使用require。
define(function(req, exports) { var cache = require('cache'); // ... exports.bind = bind; exports.unbind = unbind; exports.trigger = trigger; });
看网络请求
这次“cache”模块竟然请求下来了。
仔细看上面的匿名函数代码中require没声明,且形参req而非require。那
var cache = require('cache');
中的require从何而来?
看SeaJS源码可知,它的define函数中会取该匿名函数的toString,使用正则匹配解析出其中的“cache”(私有的parseDependencies函数)。
我们也看到,虽然cache请求下来了,却仍然报错,因为在执行阶段require是未定义的。因此写依赖模块时匿名函数的第一个参数必须为require且不能更改。
正因为使用factory.toString和正则解析依赖,因此require的参数不能是表达式,如
// require的参数不能是表达式运算 require("ui-" + "dialog");
也不能使用require的别名,如
// 不能将require赋值给另外一个变量 var req = require; req("ui-dialog");
c、修改exports为expo
define(function(require, expo) { var cache = require('cache'); // ... expo.bind = bind; expo.unbind = unbind; expo.trigger = trigger; });
运行是没有问题的。即第二个参数“exports”是可以自定义的。显然SeaJS不赞成改“exports”为其它,这样明显破坏了NodeJS风格(Modules/1.1.1)的模块规范---它们正是使用“exports”导出模块接口。但这点在SeaJS中却无法被强制执行,只能是人为约定。
5、混合写法的模块
上面已经介绍了各种情形中的模块写法。为了与NodeJS风格保持一致:使用require获取“依赖”,使用exports导出“接口”。SeaJS在获取依赖这一块做了限制,即必须使用require。但导出则不一定非得使用exports,即exports可以改为其它。甚至还可以直接使用 “返回值”。
define(function(require) { var cache = require('cache'); // ... // 使用返回值导出接口 return { bind: function() {}, unbind: function() {}, fire: function() {} }; });
我们知道在NodeJS中模块只能是一个对象。即总是往exports上挂方法。SeaJS中如果使用exports导出接口,那么也一样,模块也只能是JS对象。如果使用“返回值”导出接口的话,那么模块可以是任意的JS类型。如下将返回一个函数类型的模块。
define(function(require) { var cache = require('cache'); function ad() { //... } // 函数类型的模块 return ad; });
三、SeaJS的加载方式
虽然它提供各种方式(同步异步)加载,最简单的莫过于直接在页面中写script标签。引入SeaJS后,入门多数时候就是seajs.use方法。
seajs.use有两个参数,第一个参数可以为字符串(模块名)或数组(多个模块)。第二个参数是回调函数。模块加载后的回调。回调函数的参数与第一个参数一一对应。
seajs.use('dom', function(dom) { // todo with dom });
如下将在回调函数中使用dom模块。当然它也提供了快捷方式data-main(同RequireJS)。
发表评论
-
软件复用的几种方式
2014-06-20 05:39 2558软件复用的好处有很多 一、提高工作效率 这条自不 ... -
Backbone模型
2014-05-05 11:09 1144现在进入最关键的组 ... -
Backbone.sync-将模型同步到服务器
2014-05-05 10:52 1057默认情况下,只要保存模型(Model/Collection的 ... -
Backbone事件模块
2014-04-29 13:58 3054事件模块Backbone.Events是Backbone的 ... -
Backbone的写类方式
2014-04-22 07:58 1060从两个角度去讨论Backbone的写类方式 Backb ... -
基于CommonJS Modules/2.0的实现:BravoJS
2013-05-16 16:53 1650今天看见一个基于CommonJS Modules/2.0的 ... -
RequireJS和Backbone的集成
2013-05-16 07:15 3731有朋友留言RequireJS如何与Backbone集合使用 ... -
RequireJS进阶(三)
2012-07-16 17:32 5013进阶的前面两篇讲述了r.js如何通过命令行把所有的模块压缩为一 ... -
RequireJS进阶(二)
2012-07-12 12:04 1869这一篇来认识下打包工具的paths参数,在入门一中就介绍了re ... -
RequireJS进阶(一)
2012-07-03 18:00 1932为了应对日益复杂,大规模的JavaScript开发。我们化整为 ... -
RequireJS 2.0 正式发布
2012-06-05 18:13 1773就在前天晚上RequireJS发布了一个大版本,直接从vers ... -
RequireJS入门(三)
2012-06-04 09:36 1937这篇来写一个具有依赖的事件模块event。event提供三个方 ... -
RequireJS入门(二)
2012-06-03 19:18 2013上一篇是把整个jQuery库 ... -
RequireJS入门(一)
2012-05-22 16:41 2033RequireJS由James Burke创建,他也是A ... -
UMD和ECMAScript模块
2012-03-19 15:57 4308一、UMD:AMD 和CommonJS的糅合 前面花了 ... -
AMD:浏览器中的模块规范
2012-03-01 08:07 3850前面提到,为实现与NodeJS相同方式的模块写法,大牛们做了 ... -
NodeJS模块格式在浏览器中的尝试
2012-02-29 07:32 2918我们知道NodeJS有一套简洁的格式写模块,它遵循的就是 Mo ... -
拥抱模块化的JavaScript(三1)
2012-02-26 13:51 0毕竟CommonJS不是ECMAScript,浏览器厂商 ... -
拥抱模块化的JavaScript(四)
2012-02-25 18:12 0想在浏览器端实现与Node ... -
JavaScript在服务器端的模块化
2012-02-28 07:20 1444服务器端的JSer是幸运的,它有NodeJS,NodeJS遵循 ...
相关推荐
JavaScript模块化编程是现代Web开发中的重要组成部分,它有助于组织代码、提高可维护性和复用性。本篇文章将深入探讨JavaScript模块化编程的实战应用,特别是通过试用SeaJS这一工具来实现。SeaJS是一款专注于浏览器...
SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制,本文给大家介绍JavaScript模块化开发之SeaJS,需要的朋友参考下
Seajs和RequireJS是两种常见的JavaScript模块化解决方案库,它们都是基于AMD(Asynchronous Module Definition)规范的实现。 Seajs是一个轻量级的模块加载器,它的核心特性包括: 1. **模块定义**:使用`define`...
模块开发的不同写法反映了JavaScript模块化演进的过程: 1. **原始写法**:最简单的模块形式,即将一组相关的函数定义在一起。但这种方法容易导致全局命名空间的污染,且模块成员之间的关系不明显。 ```...
总结来说,SeaJS 是一个强大的JavaScript模块加载器,它遵循CommonJS规范,提供了模块化编程的支持,帮助开发者更好地组织和管理Web应用的JavaScript代码。通过异步加载、动态配置和丰富的插件系统,SeaJS 使得...
这是自己编写的模仿seajs模块加载的模块加载器,用于学习交流之用。大致模仿seajs的模块化加载实现。
以上是对 SeaJS 的快速入门介绍,通过理解并熟练运用这些概念和方法,开发者可以在浏览器端实现高效、模块化的 JavaScript 开发。在实际项目中,可以进一步探索 SeaJS 的高级特性,如插件、命令行工具等,以提升开发...
CommonJS规范旨在促进JavaScript模块化,使得代码可复用性和可维护性得到显著提升。SeaJS 的出现,使得在前端开发中可以像在服务器端使用Node.js那样,方便地进行模块化的编程。 SeaJS的核心功能包括以下几个方面:...
Seajs是一款轻量级的前端模块加载器,它遵循CommonJS规范,使得JavaScript在浏览器端也能实现模块化的开发。这个规范主要包含模块定义、模块加载和模块化开发的思想,大大提高了代码的可维护性和复用性。 1. **模块...
SeaJS是中国开源社区贡献的一款JavaScript模块加载框架,其主要目标是为Web开发提供一种遵循CommonJS规范的模块化解决方案。这个框架的版本v0.9.1是一个免费版,适用于各种项目开发,帮助开发者更有效地组织和管理...
Seajs是一款轻量级的JavaScript模块加载器,它遵循CommonJS规范,旨在解决浏览器环境中的模块化问题。在深入理解seajs源代码之前,我们首先需要了解模块化的基本概念和CommonJS规范。 模块化是软件开发中的一种组织...
Seajs的源码简洁明了,便于学习和理解,对于开发者提升JavaScript模块化理解大有裨益。同时,Seajs社区提供了如spm(Sea.js Package Manager)这样的工具,用于构建、压缩和优化Seajs项目,提高了开发效率。 7. **...
在 JavaScript 开发中,模块化是一个关键的实践,它有助于提高代码的可读性、可维护性和复用性。SeaJS 正是这样一个工具,它遵循了 CommonJS 规范,允许开发者在浏览器环境中实现类似服务器端 Node.js 的模块化开发...
总结,Seajs是一个优秀的JavaScript模块化解决方案,通过它可以轻松地实现模块化的开发,提升代码质量,简化项目管理。只需要短短的5分钟,你就能领略到Seajs的魅力,并开始使用它来优化你的前端开发流程。
Seajs是中国开源社区非常受欢迎的一款JavaScript模块加载器,它的出现为Web开发引入了CommonJS规范,使得前端开发更加模块化,便于代码管理和维护。Seajs 2.3.0是该库的一个稳定版本,提供了丰富的功能和优化。 一...
JavaScript模块化是编程实践中将大型复杂项目...综合以上,JavaScript模块化和数据推送技术是构建高性能、可扩展的Web应用的关键技术,它们分别解决了代码组织和实时数据交互的问题,是现代Web开发不可或缺的组成部分。
通过阅读Seajs的源码,我们可以深入理解JavaScript模块化的工作原理,以及如何实现一个模块加载器。 在开始阅读源码之前,我们需要了解一些基本概念。CommonJS是一个为服务器端JavaScript制定的规范,它定义了模块...