`
zhouyrt
  • 浏览: 1127161 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JavaScript模块化开发库之SeaJS

 
阅读更多

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)。

 

 

 

 

 

 

 

  • 大小: 13 KB
  • 大小: 11.5 KB
分享到:
评论

相关推荐

    JavaScript模块化开发之SeaJS

    SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制,本文给大家介绍JavaScript模块化开发之SeaJS,需要的朋友参考下

    JavaScript 模块化开发实例详解【seajs、requirejs库使用】

    本文实例讲述了JavaScript 模块化开发。分享给大家供大家参考,具体如下: JS开发的问题 冲突 依赖 JS引入的文件,产生依赖. 使用命名空间解决: 命名空间的弊端 调用的时候 名字比较长. 只能减低冲突,不能完全避免 ...

    模仿seajs模块化加载的自行实现练习

    这是自己编写的模仿seajs模块加载的模块加载器,用于学习交流之用。大致模仿seajs的模块化加载实现。

    Javascript模块化编程(三):模块化编程实战,试用SeaJS

    NULL 博文链接:https://weistar.iteye.com/blog/2029949

    JS模块化标准技术.JAVASCRIPT的几种模块化技术

    JS模块化标准技术.JAVASCRIPT的几种模块化技术 作为前端重要组成部分的javascript语言,其面向对象功能非常差.所以要实现代码的模块化,需要一些标准:...针对2种模块化也有现成的js模块化库SeaJs,require.js 今天来个教程

    seajs代码以及文档,帮助你学习。

    SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。与jQuery等JavaScript框架不同,SeaJS不会扩展封装语言特性,而只是实现JavaScript的模块化及按模块加载。

    seajs模块加载框架

    SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。

    JavaScript模块化编程

    介绍js编程中使用模块化方式进行代码编写,模块化一种将系统分离成独立功能部分的方法,可将系统分割成独立的功能部分,严格定义模块接口、模块间具有透明性

    通过seajs实现JavaScript的模块开发及按模块加载

    用来解决繁琐的js命名冲突,文件依赖等问题,其主要目的是令JavaScript开发模块化并可以轻松愉悦进行加载。 首先看看seajs是怎么进行模块开发的。使用seajs基本上只有一个函数“define” fn.define = function(id, ...

    SeaJS入门教程系列之SeaJS介绍(一)

    前言SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。与jQuery等JavaScript框架不同,SeaJS不会扩展封装语言特性,而只是实现JavaScript的模块化及按模块加载。...

    ES6中module模块化开发实例浅析

    多人开发JavaScript时伴随着命名冲突等问题,先后有了模拟块级作用域、命名空间、模块化开发等方法。 之前,模块化开发一直是由第三方库来模拟的,比较知名的有AMD规范和CMD规范。 两个规范分别对应requirejs和seajs...

    JavaScript的模块化开发框架Sea.js上手指南

    |-- sea-modules 存放 seajs、jquery 等文件,这也是模块的部署目录 |-- static 存放各个项目的 js、css 文件 | |-- hello | |-- lucky | `-- todo `-- app 存放 html 等文件 |-- hello.html |-- lucky.html...

    Require-Seajs:js模块化

    Require-Seajs随着现在web应用越来越复杂,所需的页面越来越多,js代码也随之大量增加,而传统的[removed][removed]js加载方法会影响性能和后期的维护成本, 所以模块化js是大势所趋。模块化js将业务逻辑相关的代码...

    sea.js模块化加载框架

    javascript模块化开发所以使用的 - seajs模块加载框架 Sea.JS 是一个遵循 CommonJS 规范的模块加载框架,可用来轻松愉悦地加载任意 JavaScript 模块。 SeaJS 支持的标准模块遵循 Modules/Wrappings 规范的 define ...

    seajs和requirejs模块化简单案例分析

    主要介绍了seajs和requirejs模块化,结合具体案例形式分析了seaj和requirejs模块化应用的相关操作技巧与使用注意事项,需要的朋友可以参考下

    SeaJS入门教程系列之使用SeaJS(二)

    下载及安装 要在项目中使用SeaJS,你所有需要做的准备工作就是下载sea.js然后...在讨论SeaJS的具体使用前,先介绍一下SeaJS的模块化理念和开发原则。使用SeaJS开发JavaScript的基本原则就是:一切皆为模块。引入SeaJS后

Global site tag (gtag.js) - Google Analytics