seajs的作用:
当你的网站开发越来越复杂的时候,会经常遇到这些问题吗?
冲突
性能
依赖
seajs如何解决?
①引入sea.js的库
②如何变成模块?
define 在模块grunt合并的时候 define里面要多2个参数 一个id ,一个依赖模块的数组
③如何调用模块?
exports
seajs.use
④如何依赖模块?
require https://github.com/seajs/seajs/issues/259 requie还是严格书写约定不能被修改。 (但是自己在rrd上却看到被修改了很疑惑)
深入学习seajs
define
require
seajs.use
seajs.config
alias
preload
debug
模块化历史:
ECMAScrpt第六版将正式支持模块语法
nodeJS
commonJS
AMD
requireJS
跟seajs一样,web端模块化
seajs采用cmd规范
/*
* 使用步骤。
1、引入seajs
2、定义define模块
3、 模块的调用 seajs.use
4 、如何依赖模块(模块之间的依赖) require()
* 步骤二:
define参数说明 require 请求地址 exports 对外提供接口对象。define中的三个参数可以都写,可以都不写,可以只有前1个,可以只有前2个。
*步骤三:seajs.use参数说明 如seajs.use('./js/jq.js',function(ex){ dosomething....}) 有2个参数, 第一个参数是请求的模块地址;第二个参数是回调函数其中回调函数中的参数是模块返回的接口对象。*步骤四:require 例子define(function(require,exports,module){
* var a=require('js/module3.js').a; 当这个require方法引入的是sea模块时候,require执行完后返回的结果就是exports接口对象;
* 上面的例子就是把module3里面暴露的 a属性复制给这个模块 的a ,在本模块就可以直接使用
*});
*
*================
* 注意:在sea.js请求成功以后,请求的默认路径都会是sea.js的路径,
* 特别注意,[ 有些版本 ]加入sea.js的父级或者祖辈父级有名字为‘seajs’的文件夹,那么会以seajs这个文件夹路劲为基础路径
* 如:在index.html使用seajs.use('js/jq.js')中的的jq.js的路劲是在seajs文件夹下面的
* 但是index.html为seajs.use('./js/jq.js')时,jq.js是相对index.html的路径
*/
=====在2.1版本的更新
-
seajs.config
中,去除 plugins 和 preload 功能。 在内部实现上,plugins 是通过 preload 来实现的。但 preload 严格意义上来说,并不是 Sea.js 需要去承担的职责。去除 preload 后,plugins 的加载也变得简单,直接通过 script 提前引入就好,或者通过 combo 服务与 sea.js 一起加载。 -
去除对循环依赖的支持。目前 Sea.js 是支持循环依赖的,当有死循环时,也会给出适当的提示。但就如 Go 语言设计者所说,支持循环依赖,看起来很 cool,也能在某些场景下给设计带来简化,但从长远上来,支持循环依赖,会给整体增加复杂性,让依赖关系等都变得复杂。从这个角度上,对循环依赖的支持是一种心理上的完美,而非工程上的完美。去除对循环依赖的支持,有两个做法:1)保留循环依赖时的提示功能,这样对代码层面其实不会有太多精简。2)彻底去除,根本不考虑,有死循环时,自然的报错(比如浏览器的提示)。具体怎么做还有纠结。
-
去除对 data-config / data-main 的支持。 这两个是锦上添花的功能。保留着,看似能带来简洁性,但一定程度上掩盖了内部机制。不如让用户直接通过
seajs.use
去启动加载的好。 -
define(id, fn) 的支持。 2.0 中只支持
define(fn)
和define(id, deps, fn)
,考虑将对define(id, fn)
的支持再加回来。在手写 id 的情况下,这种写法还是蛮方面的。 -
config 中的 alias 改名叫 aliases。 原来的命名是个错误,应该统一用复数形式。这个不一定修改,也许保留这个错误也没问题。
(1)seajs 2.0版本用shim 加载非cmd模块
shim 插件
Sea.js 中的模块默认都遵守 CMD 规范,但现实中已存在大量普通 JavaScript 类库,比如 jQuery、Underscore 等。使用 shim 插件,可以将这些普通 JS 文件转换成 CMD 模块,从而能在 Sea.js 中正常使用。
激活 shim 插件:
seajs.config({
plugins: ['shim']
});
一旦激活后,alias
配置项就可以接受 shim Object
配置。
seajs.config({
// 激活 shim 插件
plugins: ['shim'],
// shim 配置项
alias: {
// jQuery 的 shim 配置'jquery': {
src: 'lib/jquery-1.9.1.min.js',
exports: 'jQuery'
},
// jquery.easing 插件的 shim 配置'jquery.easing': {
src: 'lib/jquery.easing.1.3.js',
deps: ['jquery']
}
}
});
shim Object
shim Object
是一个对象:
'key': {
src: String,
deps: Array,
exports: String | Function
}
src
是字符串,表示文件路径。
deps
是数组,指定模块依赖。
exports
表示 require(key)
时应该返回哪个全局变量,比如 jquery 的是返回 jQuery
全局变量。exports
也可以是一个函数:
'jquery': {
'src': 'lib/jquery-1.9.1.min.js',
exports: function() {
return jQuery.noConflict();
}
}
通过 shim 插件,可以加载任何非 CMD 模块。
(A)从 Sea.js 2.1 开始已经去除该插件,非常不推荐使用。
define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。
factory 为对象、字符串时,表示模块的接口就是该对象、字符串。
factory 为函数时,表示是模块的构造方法。
用来定义模块。SeaJS 推崇一个模块一个文件,遵循统一的写法:
define(function(require, exports, module) {
// 模块代码
});
也可以手动指定模块 id 和依赖,require, exports 和 module 三个参数可酌情省略,具体用法如下。
define 也可以接受两个以上参数。字符串 id 表示模块标识,数组 deps 是模块依赖。在开发阶段,推荐不要手写 id 和 deps 参数,因为这两个参数可以在构建阶段通过工具自动生成。
define(id, deps, factory)
define(‘hello’, [‘jquery’], function(require, exports, module) {
// 模块代码
});
require 是一个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口。
define(function(require, exports) {
// 获取模块 a 的接口
var a = require(‘./a’);
// 调用模块 a 的方法
a.doSomething();
});
在书写模块代码时,必须遵循这些规则。其实只要把 require 看做是语法关键字 就好啦。require 的参数值 必须 是字符串直接量。不要重命名 require 函数,或在任何作用域中给 require 重新赋值。模块 factory 构造方法的第一个参数 必须 命名为 require 。
exports 是一个对象,用来向外提供模块接口。
define(function(require, exports) {
// 对外提供 foo 属性
exports.foo = ‘bar';
// 对外提供 doSomething 方法
exports.doSomething = function() {};
});
除了给 exports 对象增加成员,还可以使用 return 直接向外提供接口。
define(function(require) {
// 通过 return 直接提供接口
return {
foo: ‘bar’,
doSomething: function() {};
};
});
如果 return 语句是模块中的唯一代码,还可简化为:
define({
foo: ‘bar’,
doSomething: function() {};
});
提示:exports 仅仅是 module.exports 的一个引用。在 factory 内部给 exports 重新赋值时,并不会改变 module.exports 的值。因此给 exports 赋值是无效的,不能用来更改模块接口。
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
module.id 模块的唯一标识。
define(‘id’, [], function(require, exports, module) {
// 模块代码
});
上面代码中,define 的第一个参数就是模块标识。
module.exports 当前模块对外提供的接口。
传给 factory 构造方法的 exports 参数是 module.exports 对象的一个引用。只通过 exports 参数来提供接口,有时无法满足开发者的所有需求。 比如当模块的接口是某个类的实例时,需要通过 module.exports 来实现:
define(function(require, exports, module) {
// exports 是 module.exports 的一个引用
console.log(module.exports === exports); // true
// 重新给 module.exports 赋值
module.exports = new SomeClass();
// exports 不再等于 module.exports
console.log(module.exports === exports); // false
});
define("examples/hello/1.0.0/main", ["./spinning", "jquery"], function(a) { var b = a("./spinning"), c = new b("#container"); c.render() }),
开发阶段不推荐define的参数传入三个,第一个参数字符串 id 表示模块标识,其实只需给定后面的factory即可,发布时通过构建工具提取压缩模块,会自动加上idhe依赖数组(即第二个参数),这样seajs能够更快的定位本身这个模块和它依赖的模块。顺便提一下,第二个参数,如果显示传入了,那么seajs就不会再通过正则去扫描factory.toString(),直接根据这个参数去加载依赖模块,如果为[]即表示无依赖。