seajs之define函数

本文介绍 seajs 的模块定义方式。

define(factory) 函数定义模块

seajs 中,使用 define 函数来定义一个模块,其接受 id , dependencies 和一个工厂函数 factory 作为参数。其中,前两个参数可选。

1
2
3

define(id?, dependencies?, factory);

id 参数

当前模块的唯一标识。该参数可选。如果没有指定,默认为模块所在文件的访问路径。如果指定的话, 必须是顶级或绝对标识(不能是相对标识)。

dependencies 参数

当前模块所依赖的模块,是一个由模块标识组成的数组。该参数可选。如果没有指定,模块加载器会从 factory.toString() 中解析出该数组。

注意:强烈推荐不要设定 id 和 dependencies 参数。 在开发阶段,模块加载器会自动获取这两个参数。部署上线时,则可以通过优化工具来提取这两个参数。

factory 参数

模块的工厂函数。模块初始化时,会调用且仅调用一次该工厂函数。factory 可以是函数, 也可以是对象、字符串等任意值,这时 module.exports 会直接设置为 factory 值。

factory 函数在调用时,会始终传入三个参数: require、exports 和 module, 这三个参数在所有模块代码里可用。

1
2
3
4
5
6
7

define(function (require, exports, module) {

// The module code goes here...

});

require 函数

require 函数用来访问其他模块提供的 API。

1
2
3
4
5
6
7
8
9
10
11

define(function( require, exports , module ){

// 访问 util.js 模块

var util = require('/utils/util')

// do something...

})

require.async 异步加载函数

该方法可用来异步加载模块,并在加载完成后执行回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

define( function(require, exports, module) {

// 加载一个模块
require.async('./b', function(b) {

b.doSomething();

});


// 加载多个模块
require.async(['./c', './d'], function(c, d) {

// do something

});

});

require.resolve 函数

使用 require() 的内部机制来解析并返回模块路径。该函数不会加载模块,只返回解析后的路径。

require.load 函数

该方法可用来异步加载脚本,并在加载完成后,执行指定的回调函数。开发插件时, 可以通过覆盖该方法来实现自定义的资源加载。

require.constructor 属性

有时候,我们需要给所有 require 参数对象添加一些公用属性或方法。这时, 使用 require.constructor 来实现会非常方便。

exports 对象

我们可以在 exports 对象上挂载对外的接口。

1
2
3
4
5
6
7
8
9
10
// foo.js
define(function( require, exports , module ){

exports.foo = function(){

console.log('this is foo module')

}

})

如上代码所示,我们定义了一个 foo.js 模块,并向外导出了一个 foo 方法。那么,我们可以这样在其他模块中使用她:

1
2
3
4
5
6
7
8
9
10
11
define(function( require, exports , module ){

// 引入 foo.js 模块,假设该文件在根目录下的 some 文件夹下

var foo = require('/some/foo');

// 使用 foo() 方法

foo.foo() // this is foo module

})

module 对象

我们也可以使用 module.exports 对象向外导出接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// bar.js
define(function( require, exports , module ){

// some code ...

module.exports = {

name: 'bar',

bar: function(){

console.log('this is ' + this.name + 'module')

}

}

})

如上代码所示,我们在 bar.js 模块中导出了对象作为对外接口。我们在引用她试试:

1
2
3
4
5
6
7
8
9
10
define(function( require, exports , module ){

// 引入 bar.js 模块,假设该文件在根目录下的 some 文件夹下
var bar = require('/some/bar')

// 调用
bar.bar() // this is bar module

})

module.id 属性

当前模块的唯一标识。 require(module.id) 必然返回此模块的 exports。

1
2
3
4
5
6
7
8
define(function(require, exports, module) {

console.log(module.id); // http://path/to/this/file.js

console.log(require(module.id) === exports); // true

});

module.dependencies 属性

module.dependencies 是一个数组,表示当前模块的依赖列表。该数组只读:模块加载完成后,修改该数组不会有任何效果。

module.exports 对象

exports 对象由模块系统创建,这不能满足开发者的所有需求, 有时候会希望 exports 是某个类的实例。 这时可用 module.exports 来实现:

1
2
3
4
5
6
7
8
9
10
11

define(function(require, exports, module) {

console.log(module.exports === exports); // true

module.exports = new SomeClass();

console.log(module.exports === exports); // false

});

注意,对 module.exports 的赋值需要同步执行,它不能放在回调函数里。 下面这样是不行的。

x.js

1
2
3
4
5
6
7
8
9
10
11

define(function( require, exports , module ){

setTimeOut(function(){

module.exports = { name: 'a' }

})

})

y.js

1
2
3
4
5
6
7
8
9

define(function( require, exports , module ){

var x = require('./x')

console.log(x.name) // undefined

})

module.constructor 属性

有时候,我们需要给所有 module 参数对象添加一些公用属性或方法。在这种情况下, 使用 module.constructor 可以很好地满足需求。

extend.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// extend.js
define(function(require, exports, module) {

var Module = module.constructor;

Module.prototype.filename = function() {

var id = this.id;

var parts = id.split('/');

return parts[parts.length - 1];

};

});

a.js

1
2
3
4
5
6
7
// a.js
define(function(require, exports, module) {

exports.filename = module.filename();

});

exports 和 module 的区别

sea.js 的这部分实现,借鉴了 CommonJs 规范,即 node.js 中的模块实现。也就是说,exports 只是 module.exports 的一个引用,require 函数返回的永远是 module.exports 对象。所以对于如下操作是不对的:

1
2
3
4
5
6
7
8
9
10
11

define(function( require , exports , module ){

exports = {

name: 'baz'

}

})

注:不能直接对 exports 直接重新赋值,重新赋值后,exports 就不再指向 module.exports 对象了,当你 require 该模块时,其返回的永远都是 {}