Javascript重构
Javascript重构
JavaScript重构(一):模块划分和命名空间收藏
通常我们的团队中,开发人员在Java语言层面具备相当的技术素养,经验丰富,而且有许多成熟的、合理的规约,类型繁多的代码隐患检查工具,甚至在团队间还有计划内的评审和飞检。但是前端的代码不似后台,就像一个没人疼的孩子,不仅仅容易被低估、被轻视,导致质量低劣、可维护性差,技能上,更缺少优秀的前端开发人员。
JavaScript是前台代码中重要组成部分,随着版本的延续,产品越做越大,JavaScript层面的重构,需要在整个过程中逐步强化起来。
当代码量达到一定程度,JavaScript最好能够与页面模块组件(例如自定义的FreeMarker标签)一起被模块化。
模块化带来的最大好处就是独立性和可维护性,不用在海量的js中定位问题位置,简单了,也就更容易被理解和接受,更容易被定制。
模块之间的依赖关系最好能够保持简单,例如有一个common.js,成为最通用的函数型代码,不包含或者包含统一管理的全局变量,要求其可以独立发布,其他组件js可以轻松地依赖于它。举个例子,我们经常需要对字符串实现一个trim方法,可是js本身是不具备的,那么就可以在这个common.js中扩展st ring的prototype来实现,这对外部的使用者是透明的。
使用命名空间是保持js互不干扰的一个好办法,js讲究起面向对象,就必须遵循封装、继承和多态的原则。参照Java import的用法,我希望命名空间能带来这样的效果,看一个最简单的实例吧:
我有一个模块play,其中包含了一个方法webOnlinePlay,那么在没有import这个模块的时候,我希望是js的执行是错误的:
webOnlinePlay(); //Error! 无法找到方法
但是如果我引入了这个模块:
import("play");
webOnlinePlay(); //正确,能够找到方法
其实实现这样的效果也很简单,因为默认调用一个方法webOnlinePlay()的实质是:window.webOnlin ePlay(),对吗?
所以在import("play")的时候,内部实现机制如下:
var module = new playModule();
对于这个模块中的每一个方法,都导入到window对象上面,以直接使用:
window[methodName] = module[methodName];
其实这里并没有什么玄机,但是这种即需即取的思想却给前端重构带来了一个思路,一个封装带来的可维护性增强的思路,不是吗?
聪明的你也许还会提到一个问题:
如果我没有import这个play模块,这个页面都不需要,那我能否连这个play.js都不加载呢?
当然可以,请关注后面的分解——关于js的动态加载的部分。
JavaScript重构(二):JS的动态加载收藏
前一节留下了一个问题,如果JS分门别类也清晰了,那我现在需要在必要的情况下才加载某一模块的JS,这个怎么实现呢?
方法一,最简单也是最容易被接受的方法,通过后台代码来控制,还是少些复杂的JS吧,通过一个标签、一个分支判断,就可以做到,何乐而不为呢?
方法二,如果要使用纯JS来控制,那么看看这样如何:
$.ajax(){
url:"xxx/play.js";
……
success:function(res){
eval(res.responseText);
}
}
原理是很简单,不过有一个藏匿着的魔鬼:eval,js加载的生效就靠它了,那么执行的上下文就在它的里面,这就会带来一些潜在的问题,而且,调试也变得困难。
方法三,通过添加标签的方式来动态引入脚本:
原理相信大家也马上能领悟个大概了,需要的时候动态地往页面的里面写一对标签,让浏览器自己去取需要的js,这样的就解决了方法二里面的魔鬼eval的问题,是一个比较好的方法。
这里啰嗦一句,标签中的src——本质上不就是对src所表示的地址发送一个get请求吗?这虽然看起来有点歪门邪道,却恰恰是一个跨域问题的解决办法!因为浏览器对引用js页面可没有同域的安全限制(以前转载过过一篇跨域问题的讨论,见此)。
另外,如果使用上pushlet的方法,对一个js文件无止境地读取,能否实现这样的效果呢?仅作设想,希望有人与我讨论。
进行JavaScript重构时,我希望引入易于使用的测试框架来保证重构的顺利进行,未来能持续通过测试代码对JavaScript逻辑的正确性做保障。
JsUnit (https://www.360docs.net/doc/a29505624.html,/projects/jsunit/,https://www.360docs.net/doc/a29505624.html,/)
JsUnit是一个独立的JavaScript单元测试框架,和JUnit差不多,没有上手难度,包括传统的setUp和tearDown,提供的assert方法也和JUnit类似,多了assertNaN和assertUndefined等等JavaScript 特有的方法。测试页面必须在里面引入jsUnitCore.js这个js文件。
测试套件的支持:提供了addTestPage和addTestSuite;
测试日志的支持:包括warn、info和debug三种日志级别,前端编码不似后台代码,正式代码中不宜使用过多log,再说log也只有FF下才支持,现在好了,在测试代码里尽情打吧。
千言万语不及一个例子:
< language="javascript" src="jsUnitCore.js">< language="javascript" src="play.js"> //模块JS< language="javascript">
function testWithMainProcess() {
assertEquals("Web play url", "##http://...##", webOnlinePlay());
}
项目的代码里到处是Ajax调用,要做单元测试,看来打桩是不可避免了。Mock 类的工具有许多,比如适合JQuery的QMock:
var mockJquery = new Mock();
mockJquery
.expects(1)
.method('ajax')
.withArguments({
url: 'http://xxx,
success: Function,
dataType: "jsonp"
})
.callFunctionWith({ feed : { entry : "data response" }});
这个桩正是mock了一个假的ajax jason返回:[feed:[entry:"data response"]],看看,使用就和以前接触过的EasyMock差不多嘛。
对于JavaScript测试框架感兴趣的同学还可以了解一些其他的测试框架,例如JSpec。
单元测试代码建议就放在模块的包内:test.html,即便理想状况下,模块单独发布时,也是伴随着测试用例的可靠的前端代码。
从哪些JavaScript代码开始做?
1、函数式的代码。这样的代码保证独立性好,也不需要打什么桩,测试成本低,如果不明白函数式的代码的含义,请参见“函数式编程”。
2、复杂的逻辑。
是否尝试TDD?不建议在我们团队内部使用,前端TDD需要更高的技巧,对人的因素要求更高。如果有一天,后台Java代码的TDD做好了,那么换成JavaScript的代码,没有本质区别。
如果效果得当,为什么不能把JavaScript的UT集成到ICP-CI上作为持续集成的一部分呢?
没有规矩,不成方圆,JavaScript带来了灵活性,也带来了不受控的变量和访问,所以要用规则限制它。一支成熟的团队,还是一支新鲜的团队,规则应当是不一样的,我只是列出一些常见的或者有效的办法,来约束跳跃的开发人员,思维可以任意飞跃,代码却要持续受控。当然,任何规则都是建立在一定的认知基础之上的,面向对象JavaScript的基础是必备的,否则一切无从谈起。
变量和方法控制:
模块开发不允许存放独立的全局变量、全局方法,只允许把变量和方法放置到相应模块的“命名空间”中,对此的解释请参见此文。如果实在心痒了,那么使用匿名函数如何?
(function() {
var value = 'xxx';
var func = function() {...};
})();
模块化需要严格控制住代码的区域性,这不仅仅是代码可维护性、可定制性的一方面,同时也让JavaScript 引擎在属性和方法使用完毕后及时地回收掉。
不允许在模块代码中污染原生对象,例如
String.prototype.func = new function(){...};
如此的代码必须集中控制,例如统一放置在common.js中,严格保护起来。
数据存放约束:
临时数据和prototype的数据分而治之,这点很像Java类中的dynamic属性和static的属性,对于prototype的属性,建议在模块定义代码中统一管理,比如这样如何:
function T(name){
T.prototype._instance_number++;
https://www.360docs.net/doc/a29505624.html, = name;
this.showName=function(){
alert(https://www.360docs.net/doc/a29505624.html,);
}
};
T.prototype = {
_instance_number:0,
_showInstanceNum: function(){
alert(T.prototype._instance_number);
}
};
var t = new T("PortalONE");
t.showName();
new T("Again");
t._showInstanceNum(); //打印:2
这里的办法就是把prototype的方法和属性的命名都以下划线开头了,如果这段代码都看不懂的话,赶紧温习一下面向对象的JavaScript吧:)。
另外,优先使用JavaScript的原生对象和容器,比如Array,Ajax的数据类型统一切到JSON上来,并且,通常是不允许随意扩展DOM对象的。
至于模块间的通信:模块间的通信意味着模块间的耦合性,是需要严格避免的;通信的途径通常使用模块级的prototype变量。
DOM和CSS操纵规则:
在模块代码中,通常要求把对DOM的操纵独立到模块js中,应当避免在DOM模型上显示地写时间触发函数,例如:
借助JQuery基于bind的一系列方法,把行为逻辑独立出来以后,完全可以看到清爽的HTML标签。CSS的样式控制包括:
(1)拒绝style="xxx"的写法,主要目的是将样式统一到主题样式表单中,当然主题样式表单也是按模块存放的,对于不同语种的定制和不同风格的切换带来便利。
(2)在使用JavaScript控制样式变化时,鼓励使用样式定义的切换,而不是具体样式名的切换,即鼓励使用:
$("#bar").css("enabled");
以上只能算冰山一角,抛砖引玉,实际项目中需要在开发过程中逐步细化和完善。
JavaScript入门教程(初学者不可多得的优秀入门教材,通俗易懂,专业术语通俗化)
第 1 章 JavaScript 语言入门 1 为什么学习 JavaScript
提要:Javascript 是学习脚本语言的首选。她兼容性好,绝大多数浏览器均支持 Javascript,而且她功能强大,实现简单方便,入门简单,即使是程序设计新手也可以非常 快速容易地使用 JavaScript 进行简单的编程。
Javascript 是由 Netscape 公司创造的一种脚本语言。为便于推广,被定为 javascript,但 是 javascript 与 java 是两门不相干的语言, 作用也不一样。 作为一门独立的编程语言, javascript 可以做很多的事情,但它最主流的应用还是在 Web 上——创建动态网页(即网页特效)。 Javascript 在网络上应用广泛, 几乎所有的动态网页里都能找到它的身影。 目前流行的 AJAX 也是依赖于 Javascript 而存在的。 Javascript 与 Jscript 也不是一门相同的语言, Jscript 和 vbscript 是微软开发的两种脚本语 言,微软,Netscape 公司以及其他语言开发商为减少 web 开发者的兼容麻烦,所以成立 ECMA , 该组 织 专 门制定 脚 本 语 言的 标 准 和规范 。 ECMA 制 定 的标 准脚 本 语 言 叫做 ECMAScript,Javascript 符合 ECMA 的标准,其实 Javascript 也可以叫做 ECMAScript. Jscript 也 ECMA 的标准, 但用户较少。vbscript 仅局限在微软的用户, Netscape 不支持。 概括地说,JavaScript 就是一种基于对象和事件驱动,并具有安全性能的脚本语言,脚 本语言简单理解就是在客户端的浏览器就可以互动响应处理程序的语言, 而不需要服务器的 处理和响应,当然 JavaScript 也可以做到与服务器的交互响应,而且功能也很强大。而相对 的服务器语言像 asp https://www.360docs.net/doc/a29505624.html, php jsp 等需要将命令上传服务器,由服务器处理后回传处理结 果。对象和事件是 JavaScript 的两个核心。 JavaScript 可以被嵌入到 HTML 文件中,不需要经过 Web 服务器就可以对用户操作作 出响应,使网页更好地与用户交互;在利用客户端个人电脑性能资源的同时,适当减小服务 器端的压力,并减少用户等待时间。
2 将 JavaScript 插入网页的方法
与在网页中插入 CSS 的方式相似,使用
language="javascript"表示使用 JavaScript 脚本语言,脚本语言还有 vbscript、 jsscript 等,如果没有 language 属性,表示默认使用 JavaScript 脚本。其中的...就是代 码的内容。例如:
asp动态生成的javascript表单验证代码
以网上down了一个asp动态生成form验证javascript的代码,自己扩容了一下。作者的大名我给忘了,不过我记得清楚,从第一条至第九条的代码都是该作者的原创。至于九至第十五条却是本人自己加的哦。而且由于本人水平有限,从第九条至第十五条不见得会条条生效啊?呵呵,其实把它贴在这里没有什么必要的,因为这点小会伎俩谁都会用的,我把它的作用定位为:开发时找不到该函数时到这里拷贝一下就可以了。呵,因为我即没有刻录机也没有移动硬盘。实在是没有办法把这些代码随身携带,不过还好,在北京到处都可以上网。所以就把这个放在这里,用的时候ctrl+c,再ctrl+v好了。 <% '**************************************************************** '函数名称:checkform_js(frmname,errstr) '功能:用asp的方法动态写出javascript的表单验证的函数checksubmit() '使用方法:1、&vbcrlf&_ response.write strshow end sub function findjs(frmname,errstr) dim tmparr dim i '参数值 i=0 '获取错误列表,建立数组 tmparr=split(errstr,|) '输出查询条件 select case tmparr(i+1) case 0 '必填的text类型 findjs=if ((document.&frmname&.&tmparr(i)&.value)==)&vbcrlf&_ {&vbcrlf&_ window.alert ('&tmparr(i+2)&');&vbcrlf&_ document.&frmname&.&tmparr(i)&.select();&vbcrlf&_ document.&frmname&.&tmparr(i)&.focus();&vbcrlf&_ return false;&vbcrlf&_ }&vbcrlf exit function case 1 '必填的listmenu类型 findjs=if ((document.&frmname&.&tmparr(i)&.value)==)&vbcrlf&_ {&vbcrlf&_ window.alert ('&tmparr(i+2)&');&vbcrlf&_ document.&frmname&.&tmparr(i)&.focus();&vbcrlf&_ return false;&vbcrlf&_ }&vbcrlf exit function
JavaScript实验
实验项目:浏览器脚本语言及其应用 实验类型:设计 实验课时:4 实验目的:研究javascript及其应用 实验方案: 1 研究将JavaScript引入HTML页面 创建一个HTML文件,容如下。在浏览器中打开该文件。分析代码。
3 研究JavaScript名称 创建一个HTML文件,容如下。在浏览器中打开该文件。分析代码。 3 研究JavaScript值 创建一个HTML文件,容如下。在浏览器中打开该文件。分析代码。