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

seajs基础学习

阅读更多
作者:zccst

学习几天seajs了,发现seajs就是一个模块管理工具,唉。

既然自立门户,肯定就会有一些规则,原来CMD也是国人提出来的,赞一个。

现在就来学习吧,今天是第二次看seajs,对于第一次

1,define();写法
define(function(require, exports, module){
});


2,require书写规则
(1)拼写完整,正确
(2)不要修改。不能在任何作用域中给require重新赋值。
(3)require必须是直接量字符串。不能require一个变量;字符串拼接等;字符串函数
为什么 require 要有书写约定
在开发时,Sea.js 是如何知道一个模块的具体依赖呢?
a.js
define(function(require, exports) {
  var b = require('./b');
  var c = require('./c');
});
Sea.js 在运行 define 时,接受 factory 参数,可以通过 factory.toString() 拿到源码,再通过正则匹配 require 的方式来得到依赖信息。依赖信息是一个数组,比如上面 a.js 的依赖数组是:['./b', './c']
由于 Sea.js 的这个实现原理,使得书写 CMD 模块代码时,必须遵守 require 书写约定,否则获取不到依赖数组,Sea.js 也就无法正确运行。



3,exports
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() {}
});
上面这种格式特别适合定义 JSONP 模块。

特别注意:下面这种写法是错误的!
define(function(require, exports) {
  // 错误用法!!!
  exports = {
    foo: 'bar',
    doSomething: function() {}
  };
});
正确的写法是用 return 或者给 module.exports 赋值:
define(function(require, exports, module) {
  // 正确写法
  module.exports = {
    foo: 'bar',
    doSomething: function() {}
  };
});
提示:exports 仅仅是 module.exports 的一个引用。在 factory 内部给 exports 重新赋值时,并不会改变 module.exports 的值。因此给 exports 赋值是无效的,不能用来更改模块接口。


4,module
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
(1)module.id  String  模块的唯一标识。
define('id', [], function(require, exports, module) {
  // 模块代码
});
上面代码中,define 的第一个参数就是模块标识。

(2)module.uri  String 根据模块系统的路径解析规则得到的模块绝对路径。
define(function(require, exports, module) {
  console.log(module.uri);
  // ==> http://example.com/path/to/this/file.js
});
一般情况下(没有在 define 中手写 id 参数时),module.id 的值就是 module.uri,两者完全相同。

(3)module.dependencies   Array  dependencies 是一个数组,表示当前模块的依赖。

(4)module.exports   Object  当前模块对外提供的接口。
传给 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
});
注意:对 module.exports 的赋值需要同步执行,不能放在回调函数里。下面这样是不行的:
// x.js
define(function(require, exports, module) {
  // 错误用法
  setTimeout(function() {
    module.exports = { a: "hello" };
  }, 0);
});
在 y.js 里有调用到上面的 x.js:
// y.js
define(function(require, exports, module) {
  var x = require('./x');
  // 无法立刻得到模块 x 的属性 a
  console.log(x.a); // undefined
});


自己的测试:
把工具文件util.js写成
define(function(require, exports) {
  exports.each = function (arr) {
    // 实现代码
  };
  exports.log = function (str) {
    // 实现代码
  };
});
通过 exports 就可以向外提供接口。这样,dialog.js 的代码变成
define(function(require, exports) {
  var util = require('./util.js');
  //util返回的一个对象,可以使用util.each和util.log
  //不过util到底是一个对象还是函数,取决于你在util.js的exports中如何暴露接口的
  exports.init = function() {
    // 实现代码
  };
});
关键部分到了!我们通过 require('./util.js') 就可以拿到 util.js 中通过 exports 暴露的接口。这里的 require 可以认为是 Sea.js 给 JavaScript 语言增加的一个 语法关键字,通过 require 可以获取其他模块提供的接口。

好好琢磨以上代码,我相信你已经看到了 Sea.js 带来的两大好处:
(1)通过 exports 暴露接口。这意味着不需要命名空间了,更不需要全局变量。这是一种彻底的命名冲突解决方案。
(2)通过 require 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖,其他事情 Sea.js 都会自动处理好。对模块开发者来说,这是一种很好的 关注度分离,能让程序员更多地享受编码的乐趣。




5,动态依赖 require.async
if (todayIsWeekend)
  require("play");
else
  require("work");
从静态角度,这个模块同事需要play和work两个模块,所以加载器会把这两个模块文件都下载下来。这种情况下,推荐使用require.async进行条件加载。

require.async  用来在模块内部异步加载一个或多个模块。

define(function(require) {
  // 异步加载一个模块,在加载完成时,执行回调
  require.async('./b', function(b) {
    b.doSomething();
  });
  // 异步加载多个模块,在加载完成时,执行回调
  require.async(['./c', './d'], function(c, d) {
    c.doSomething();
    d.doSomething();
  });
});
注意:require 是同步往下执行,require.async 则是异步回调执行。require.async 一般用来加载可延迟异步加载的模块。


小结

这就是 CMD 模块定义规范的所有内容。经常使用的 API 只有 define, require, require.async, exports, module.exports 这五个。其他 API 有个印象就好,在需要时再来查文档,不用刻意去记。

与 RequireJS 的 AMD 规范相比,CMD 规范尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。通过 CMD 规范书写的模块,可以很容易在 Node.js 中运行,后续会介绍。


如果您觉得本文的内容对您的学习有所帮助,您可以微信:
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics