Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
goto100 edited this page May 24, 2012 · 4 revisions

概览

  • 在objectjs中,代码的最基本组织形式是 模块 。除了浏览器原生成员,任何代码成员都应该属于某个模块;
  • objectjs中的模块只有在 被调用时 才会被执行,因此,它具有沙箱的特性,多次调用过程中,产生的模块实例不是同一个,避免了全局污染;

模块定义

object.define

object.define(id, dependencies?, factory);

id

当前模块的唯一标识,一般为一个路径;

dependencies

当前模块的依赖模块,用“,”(逗号)分隔,也可以传递一个数组,如['dom', 'events']

objectjs的Loader的创新点在于,在兼容CommonJS形式的模块的同时,支持传统的命名空间式 子模块 ,且两种模块可一起使用。两种形式是:

  • CommonJS形式,为一个路径形式,如a/b/c./b
  • ObjectJS形式,为命名空间形式,如a.b.c

两种依赖的区别是:

  • CommonJS依赖支持相对依赖,如./b则代表当前模块下名为b的模块;
  • ObjectJS依赖支持子模块,如依赖名为a.b.c的模块时,可通过获取到a的引用,调用a.b.c上的成员,同传统的 命名空间 式相同;
  • ObjectJS依赖的子模块在调用时会自动初始化其父模块;
  • 通过object.define指定了路径形式的id的模块,可直接通过ObjectJS的依赖形式获取其引用。

假设已定义3个模块,分别为aa/ba/b/c。 示例:

  • 定义a模块时,可通过./b依赖获取到a/b模块的引用;
  • 可通过a.b.c形式的依赖,将a/b模块的引用放到a模块的b成员上,将a/b/c模块的引用放到a/b模块的c成员上;
  • ObjectJS形式的模块依赖,并不支持相对引用,./b.c形式的依赖会找不到模块a/b.c

factory

模块构造函数,模块初始化时,会调用此函数并传递3个参数,分别为require、exports和module。

require

通过require获取依赖模块的引用。

object.define('mymodule', 'ui, ./submodule, ui/slider, ui.popup', function(require, exports) {
	var ui = require('ui'); // ui上有popup成员,没有slider成员
	var slider = require('ui/slider');
	var submodule = require('./submodule'); // 通过相对路径获取 mymodule/submodule 模块
});

require.async

用来异步加载模块。

object.define('mymodule', function(require, exports) {
	require.async('./b, ./c', function(b, c) {
	});
});

exports

在模块构造函数内部,通过exports提供此模块的成员(同this)。

在模块构造函数内部可通过this.__name__获取到当前模块的名称。

object.define('mymodule', function(require, exports, module) {
	// 模块函数
	exports.func = function() {};

	// 模块变量,this == exports
	this.foo = 1;

	// 模块类
	exports.MyClass = new Class(function() {});
	console.log(this.__name__);
});

同时,也可通过return返回模块的成员,此时,向exports上添加的任何成员都是无效的。

object.define('mymodule', function(require, exports, module) {
	// 通过return返回模块内容
	return {
		func: function() {},
		foo: 1,
		MyClass: new Class(function() {})
	};
});

object.add

objectjs还支持一种一种类似python的模块定义方式(object.add)。

  • object.define兼容SeaJS的模块书写规范,因此也可通过维护脚本兼容nodejs的模块;而add的模块从书写上并不完全兼容;

  • object.define支持通过require.async进行异步调用,而object.add不支持;

  • 通过add定义module的优势在于减少模块名依赖模块的代码量,自动获取依赖模块引用,减少代码量;

  • 根据以上区别,建议采用object.define声明模块;

  • 两者建立的模块可以互相依赖,并无兼容性问题。

    object.add(id, dependencies?, factory);

id和dependencies方法同object.define完全一致。

factory,模块构造函数,模块初始化时,会调用此函数并传递参数,第一个参数为exports,与回调函数中的this指向同一对象,可用于输出模块成员。

依赖的模块会通过函数参数 非重复顺序引用 的形式传递给主体函数。如果依赖模块是个子模块,则属于同一个父模块的多个子模块会放于同一父模块的引用中;

在模块构造函数中通过exportsthis输出模块成员,同object.define的规则是一样的。

object.add('ui', function(exports) {
	this.test = 1;
});

object.add('myobjectmodule', 'ui/slider, ui.popup', function(exports, slider, ui) {
	// 属于同一个父模块的多个子模块会放于同一父模块的引用中,子模块在调用时会自动初始化其父模块
	console.log(ui); // ==> {test: 1, popup: <Module popup>}
}

模块执行

object.execute

将一个已命名的模块直接执行,此时此模块主体函数中获取到的this.__name____main__而不是模块名

execute方法会产生一个运行时,一个运行时中的每个模块都会有一个且只有一个唯一实例,也就是说,在一个运行时中,一个模块如果被多个模块依赖调用,获取到的实例相同。

object.execute('mymodule'); // ==> __main__

利用此特性可在模块中判断当前__name__是否为__main__得知此模块是被依赖调用的还是被直接调用的。

object.use

形式同object.add类似,只是没有第一个模块名的参数

object.use就是object.add/define和object.execute的结合,object.use会向系统中注册一个匿名模块,并立刻execute。

object.use('mymodule, dom, event', function(mymodule, dom, event) {
	mymodule.func();
	console.log(mymodule.foo); // ==> 1
	console.log(this.__name__); // ==> __main__
}

动态加载

objectjs支持动态加载,减少网络请求数。需要在网页中预留需要动态加载的模块信息:

<script type="text/javascript" data-src="http://path/to/js.js" data-module="模块名称"></script>

这样,当object.use找不到需要的module时,会通过页面中的信息进行动态加载。

为了减少网络请求数,多个模块可以放置于同一个js中。data-module属性可以设置多个模块名:

<script type="text/javascript" data-src="http://path/to/3-modules-in-1.js" data-module="module1 module2 module3"></script>

高级特性

function模块

return返回模块的形式也可以返回一个function,就实现了一个function形式的模块。

object.add('jquery', function() { function jQuery() { // ... } jQuery.ajax = function() { } // ... return jQuery; });

object.use('jquery', function(exports, $) { // $是jquery模块的引用,jquery模块是一个function,意味着这个模块除了有子成员,还可以直接被调用 $.ajax() // 调用模块的某个成员 $('.editor') // 直接调用function模块 });

sys模块

系统中有一个内置的sys模块,其中的modules成员保存了此次use产生的运行时中的所有模块实例的引用

object.use('sys, mymodule', function(exports, sys, mymodule) {

// 在这里,sys.modules 保存着所有运行过程中用到的模块的引用
console.log(sys.modules); // ==> {dom: <Module dom>, event: <Module event>, sys: <Module sys>, mymodule: <Module mymodule>}

// 这样就能实现对某个运行时的模块进行修改、扩展的功能
var _submodule = sys['mumodule.submodule'];
if (_submodule) {
	_submodule.bar = 2;
}

});

object.execute用例

object.execute可在模块中判断当前__name__是否为__main__得知此模块是被依赖调用的还是被直接调用的, 因此可以判断直接调用时可自动执行一些初始化方法,实现模块的自初始化,将初始过程隐藏。

object.add('myeditor', function() {
	// 一个编辑器

	this.listen = function() {
		var eles = document.getElementsByClassName('editor');
		// ...
		// 初始化每个元素成为编辑器
	};

	// 自初始化
	if (this.__name__ == '__main__') {
		this.listen();
	}	
});

用object.use,需要知道myeditor的listen成员并经行调用,才可以在页面中初始化

object.use('myeditor', function(exports, myeditor) {
	// object.use生成myeditor实例时this.__name__为myeditor,不会进行自初始化
	myeditor.listen();
});

或用object.execute,自动初始化,无需得知其listen成员

object.execute('myeditor'); // 此时mymodule中的this.__name__为__main__

已注册模块

可通过 object._loader.lib 查看当前页面中已经注册的所有模块列表

Morty Proxy This is a proxified and sanitized view of the page, visit original site.