公司项目最近需要将js文件迁移到seajs来进行模块化管理,由于我以前主要接触模块化开发是接触的AMD规范的requireJS,没有接触过CMD规范,而且在实际项目中还没有用过类似技术。于是,我非常兴奋的开始了seajs的学习,正好对模块化开发仰慕已久,终于有机会大展身手了!

  一开始总是有点曲折的,我照着玉伯的github上的教程一步步来,然后发现在我引入jquery的时候,require到的jquery竟然是undefined,经过一番摸索,我发现原来jquery是基于amd规范的,seajs官网的例子之所以能够成功引入jquery,是因为其jquery是采用cmd规范模块化之后的产物,而显然我从百度cdn上拿下来的jquery是没有经过该处理的。百度了一下,发现jquery想改造成seajs能引入的模块,有至少两种方法

  1.在jquery源码外层套上define,将其以cmd的规范模块化

  2.找到jquery最后几行的&&amd的条件,可以使用ctrl+f搜索amd即可找到,删掉该条件

  显然,第二种方法更为方便,改造之后,果然jquery能够正确引入了,不过据其他部门同事的反馈,改造后的jquery模块在某些情况下会出现莫名其妙的bug,据他说在ios上有bug,由于暂时没遇到bug,因此暂且还是先将jquery也封装为模块

  seajs的基本配置还是比较简单的,首先,在最前面先引入seajs本身,这应该是毋庸置疑的,然后开始配置seajs,这里我遇到一个坑,网上部分教程指出config可以使用data-config来引入,写在单独文件里,我愉快的这样做了,然后一直报错,发现路径指向错误,纠结了我半天,最后突然看到原来不知道从哪个新版本开始移除了这个属性,我的天,太逗了

废话少说,正式开始配置

 seajs.config({
base:"../sea-modules",
alias:{
"jquery":"jquery/jquery.min.js"
}
});

以下即是seajs常用属性的用法:

base提供基础路径

alias是别名,用于将较长的路径简化 以上两个参数是最基本的参数,实际上还有以下几个参数

paths:用来统一路径前缀,适用于较长的外网前缀

preload:预加载部分模块,貌似已移除

debug:设置为true开启调试模式,在控制台输出一些错误警告

map:将某个路径映射到另一个,常用于在线调试,比如spm构建得到的一般有xx.js和xx-debug.js,此时可用map将.js映射为-debug.js,方便在线调试

vars:设置seajs自带变量,可用{变量名}来获取,常用于模块路径一开始不确定的情况,例如中文或英文,zh-cn或en,该变量是加在路径上的,src="../{变量名}/main.js"

charset:引用script文件时的charset属性,默认为utf-8,该属性可以为函数,具体值为函数返回的值

另外seajs.config函数可以运行多次,多次运行会自动合并配置的参数 配置结束后,开始写入口函数

seajs.use("../static/main"); 

这是最基本的入口,use方法用来引入模块,此处我引入了main.js,也就是入口js 由于seajs是异步加载模块的,所以这里还可以加入回调函数,传入一个形参,即可获取到main模块,接下来就可以调用main暴露出来的方法 配置完,写完入口,接下来就是重头戏,写模块了 seajs遵循cmd规范,要求每个模块需要按该规范风格书写 即

define(id,dependencies,function(require,exports,module){
//前面两个参数,一个是当前模块唯一标志,一个是当前模块依赖的模块。正常情况下不必指定这两个参数,seajs会帮我们自动获取,第三个factory函数是模块的工厂函数
//require用于获取其他模块,如:
var a = require("moduleA"); //此处require内写的名称可以是具体路径,也可以是alias里定义的别名,一般写的是别名
//通过require语句执行了对应的模块函数,并返回该模块的module.exports对象
//注意,除了返回对象外,也执行了该函数,比如,该模块里如果有一句alert(1)不在exports暴露的方法里,会在require调用的同时直接执行。
a.fn();//获取到a模块后,即可调用a模块暴露出来的方法
})

以下是a模块,同样使用cmd规范

define(function(require,exports,module){
  var bb="no bb";
  exports.fn=function(){
  console.log(bb);
};
});

显然,用脚也能想到控制台会打印 “no bb”,  cmd规范里比较重要的概念就是使用exports来暴露属性或方法, 例如exports.a=3,exports.fnn=function(){}, 这样其他模块用require关键字获取到对象的同时,就能使用这些暴露出来的属性或方法了。

可能有人已经注意到了,我们的factory函数里三个参数,前面两个已经用到了,require用来获取模块,exports用来暴露模块,那第三个参数呢,有什么作用?

问得好!其实一开始我也很纳闷,这个玩意到底是干嘛的,经过一番研究,我大体上了解了这个参数 ,原来require获取到的模块实际上最后返回的是module,而调用方法也是通过module.exports获取到的 exports是module.exports的一个引用,至于为什么要拐个弯,我个人猜测有两个原因(作为一个初学者大胆的猜测,如果有误欢迎指正)

1.名字短,写的爽。好吧,我开个玩笑。

2.避免随意改动模块对象,这个才是重点,前面也强调了exports只是一个引用,其指向了module.exports的内存地址 但是引用毕竟是引用,修改引用是不会改动被引用的对象的。

举个例子说明一下。

module.exports=5;

exports=3;

此时require后返回的值就会是5,而不会是3,这就是引用和本身最大的区别。

关于这两个的区别有一个新手使用常犯的错误。好吧,我没犯过(得意中~) 某些场景里,我们频繁使用exports向外提供接口,可能写了多个exports.xxx=xxx 。

这个时候,初学者可能会想我可以这样写

exports={ 
  a:xxx,
  b:xxx,
  c:xxx
}

想想就激动啊,这样写多专业,就好像js面向对象里,给构造函数的prototype拓展方法和属性时,也会用到这种写法 。

然后,很不幸的告诉你,这种写法是错误的,至于原因嘛,还是刚刚提到的知识点,exports仅仅是module.exports的一个引用,改变exports的值并不会影响到module.exports。 所以你费尽千辛万苦简化的代码并没有什么卵用,最后require时引用的module.exports根本没有像你想的那样赋值 。

当然,这种写法的方向是正确的,确实可以简化代码,如果需要这样写,这里一般有两种写法:

方法1:

module.exports={ .... }

这种方法直接给module.exports赋值,一了百了。

方法2:

return{ .... }

利用return返回的内容默认也相当于传入了module.exports 。

到此为止,我们已经能够基本使用require来获取模块,exports来暴露接口。

但是,还没结束呢,在我学习的过程中,可不止引入了一个模块,这个时候,引入多个模块会有一个小问题。

比如

var a=require("modulessA");

var b=require("modulesB");

我引入了两个模块,一个modulesA,一个modulesB,但由于粗心,我写错了第一个模块的名字,此时获取a模块那一行会报错,从而阻塞后续代码的运行 这样会造成很不好的影响,要知道seajs的初衷就是尽量0阻塞 。

此处,seajs提供了require.async方法来异步获取模块,

var a=require.async("modulesssssA");

此时,虽然该行会报错,但不会影响后续代码的执行,这就是异步加载带来的好处,使用async时还可以传入回调函数来指定加载完之后执行的逻辑 。

谈到异步与同步,突然又想起一个需要注意的地方 ,那就是module.exports的赋值必须是同步完成,而不能放在回调函数里,。

例如

setTimeout(function(){
  module.exports=...
},0);

  此时module.exports会变为 undefined 。

  在文章的最后,还提醒大家注意到一个性能问题,那就是seajs模块化项目之后,如果功能较多,大量的模块js加载会造成大量请求,这显然对项目性能是有影响的  。

  玉伯本人是推荐是用spm工具来压缩合并这些模块,这样所有的模块会合并到一个js里,适合项目上线使用 至于spm的具体配置,本人就不详细讲解了,百度一下,你就知道。

  听我啰嗦了半天,希望初学者能对seajs有充分的了解,我本人也是初次接触,这是我学习了一天之后总结出来的一些基础知识,适用于刚刚上手的朋友,至于大牛们,还请批评指正,毕竟我的理解也比较浅薄,难免有疏漏和表达不当的地方。

  最后还啰嗦一句! seajs和requirejs感觉最大的不同在于seajs是按需加载,用到的时候再加载,而requirejs是提前加载,提前就将用到的模块写在一个数组里一开始就加载好, 至于孰优孰劣,在下也不好评价。

 

seajs学习一天后的总结归纳的更多相关文章

  1. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  2. seaJS学习资料参考

    seajs官方文档:http://seajs.org/docs/#docs http://wenku.it168.com/d_000096482.shtml http://blog.codinglab ...

  3. seaJs学习笔记之javascript的依赖问题

    之前分别为大家介绍了有关javascript中的冲突和性能问题,今天为大家介绍一下有关javascript中的依赖问题.我们将继续就之前javascript中性能问题继续介绍. 先来回顾一下性能问题的 ...

  4. C语言学习一个月后感想

    C语言学习一个月后感想 感谢李晓东老板及计算机工程师联盟的学长学姐和某神秘同级同学的辛勤指导,感谢宋雨田的督促和陪伴. 初识C的1..体会 我本以为凭借瓜皮思维和花里胡哨操作可以让我熟练地学习语言,现 ...

  5. 模块化之seaJs学习和使用

    使用seaJs也有一阵子了,一直也想抽个时间写个这方面的博客,直到今天才写……也许写的不是很完善,但跟大伙分享也是一种乐趣,不对之处欢迎指出.[抱拳] 时间有限,我这里不过多介绍前端模块化,有兴趣可以 ...

  6. seajs学习笔记

    seajs配置 seajs.config({ //别名配置 alias:{ 'es5-safe':'gallery/es5-safe/0.9.3/es5-safe', 'jquery':'jquery ...

  7. 前端MVC学习——模块发开发、seajs学习

    这份学习链接已经足够了:http://seajs.org/docs/#intro 我假设你至少已经浏览过上述链接文档.并且掌握了基本的seajs基础知识~ 手把手教你创建helloworld~ Hel ...

  8. 自学了三天的SeaJs学习,解决了前端的一些问题,与小伙伴们一起分享一下!

    我为什么学习SeaJs? [第一]:为了解决项目中资源文件版本号的问题,以及打包压缩合并等问题. [第二]:好奇心和求知欲.[我发现很多知名网站也都在使用(qq空间, msn, 淘宝等等),而且 Se ...

  9. seajs教程之seajs学习笔记 seajs.use用法

    seajs.use 用来在页面中加载模块.通过 use 方法,可以在页面中加载任意模块. 实例地址:http://www.android100.org/html/201405/23/12807.htm ...

随机推荐

  1. kernel 4.4.12 外部模块Makefile 脚本编写

    kernel 4.4.12 最简单module的编译 上一篇博客上面有一个最简单的模块源代码,今天就上一个Makefile,运行make 就可以编译一个外部的模块. vim Makefile 这个是我 ...

  2. Mongodb系统管理员权限设置

    管理员账号无法执行show dbs .show collections Js代码   { "_id" : ObjectId("52a82bb26cea234c4deb06 ...

  3. Objective-C中的浅拷贝和深拷贝(转载)

    本文转自:http://segmentfault.com/blog/channe/1190000000604331 浅拷贝 浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间.如: ...

  4. paxos(chubby) vs zab(Zookeeper)

    参考: Zookeeper的一致性协议:Zab Chubby&Zookeeper原理及在分布式环境中的应用 Paxos vs. Viewstamped Replication vs. Zab ...

  5. springMVC接受JSON异常

    在springMVC 使用@RequestBody接受Json总是报如下错误: HTTP Status 500 - Handler processing failed; nested exceptio ...

  6. 远程ssh登陆时报错:/bin/bash: Permission denied

    远程普通用户ssh登录时,提示/bin/bash: Permission denied,用户名mas,密码正确. 首先上个图,用户远程登录步骤,转自http://www.tldp.org/LDP/LG ...

  7. linux无法挂载u盘

    一般插入u盘都会自动挂载,但有时挂载不了,错误提示:can't find /dev/sdb in /etc/fstab:这时可能是U盘坏了,我们当然不希望是这样.也有可能是U盘使用的接口不对应导致系统 ...

  8. sqlserver中BCP命令导入导出

    个人自用导出文本文件命令: bcp [xxDB].[dbo].[xx_tb_name] out d:\temp\xxx.txt -c -t "\t" -T bcp是SQL Serv ...

  9. 【Java EE 学习 71 上】【数据采集系统第三天】【增加页面】【增加问题】【编辑页面,编辑问题】

    增加页面和编辑页面.增加问题和编辑问题的页面使用的都是相同的页面,最后调用的方法是saveOrUpdate方法,所以只说一个就可以了. 一.增加页面 比较简单,略.流程如下: 单击“增加页”超链接-& ...

  10. 在Mac上开启自带的Apache,httpd服务

    下面演示的是Mac自带的httpd服务 启动httpd服务 AppledeMacBook-Pro:python2_zh apple$ sudo apachectl start AppledeMacBo ...