Javascript重构

Javascript重构
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文件,容如下。在浏览器中打开该文件。分析代码。 2降序排列 数组数字大小排序

降序排列: 这里写个数组var array=[59,689,62,92,68,10]; 降序输出 ②字符串的交叉合并练习

javascript键盘事件

主要分四个部分 第一部分:浏览器的按键事件 第二部分:兼容浏览器 第三部分:代码实现和优化 第四部分:总结 第一部分:浏览器的按键事件 用js实现键盘记录,要关注浏览器的三种按键事件类型,即keydown,keypress和keyup,它们分别对应onkeydown、onkeypress和onkeyup这三个事件句柄。一个典型的按键会产生所有这三种事件,依次是keydown,keypress,然后是按键释放时候的keyup。 在这3种事件类型中,keydown和keyup比较底层,而keypress比较高级。这里所谓的高级是指,当用户按下shift + 1时,keypress是对这个按键事件进行解析后返回一个可打印的“!”字符,而keydown和keyup只是记录了shift + 1这个事件。[1] 但是keypress只能针对一些可以打印出来的字符有效,而对于功能按键,如F1-F12、Backspace、Enter、Escape、PageUP、PageDown和箭头方向等,就不会产生keypress事件,但是可以产生keydown和keyup事件。然而在FireFox中,功能按键是可以产生keypress 事件的。 传递给keydown、keypress和keyup事件句柄的事件对象有一些通用的属性。如果Alt、Ctrl 或Shift和一个按键一起按下,这通过事件的altKey、ctrlKey和shiftKey属性表示,这些属性在FireFox和IE中是通用的。 第二部分:兼容浏览器 凡是涉及浏览器的js,就都要考虑浏览器兼容的问题。 目前常用的浏览器主要有基于IE和基于Mozilla两大类。Maxthon是基于IE内核的,而FireFox和Opera是基于Mozilla内核的。 2.1 事件的初始化 首先需要了解的是如何初始化该事件,基本语句如下: function keyDown(){} document.onkeydown = keyDown; 当浏览器读到这个语句时,无论按下键盘上的哪个键,都将呼叫KeyDown()函数。 2.2 FireFox和Opera的实现方法 FireFox和Opera等程序实现要比IE麻烦,所以这里先描述一下。 keyDown()函数有一个隐藏的变量--一般的,我们使用字母“e”来表示这个变量。 function keyDown(e) 变量e表示发生击键事件,寻找是哪个键被按下,要使用which这个属性: e.which

javascript

如何把JavaScript 放入HTML 页面 上面的代码会在HTML 页面中产生这样的输出: Hello World! 实例解释: 如果需要把一段JavaScript 插入HTML 页面,我们需要使用 就可以告诉浏览器JavaScript 从何处开始,到何处结束。 document.write 字段是标准的JavaScript 命令,用来向页面写入输出。 把document.write 命令输入到之间后,浏览器就会把它当作一条JavaScript 命令来执行。这样浏览器就会向页面写入"Hello World!"。 TIY 注意:如果我们不使用

javascript实验

长江职业学院Javascript语言程序设计实验指导书 专业: 学号: 姓名: 班级: 指导老师: 软件教研室编

实验一 JavaScript基本操作 一、实验目的 熟练掌握在HTML文件中编写JavaScript程序的基本操作,及在Microsoft Internet Explorer浏览器和Netscape的Nevigator浏览器中调试JavaScript的基本操作。 二、实验内容 1、用NotePad创建一个简单的.htm文件,在Microsoft Internet Explorer浏览器中浏览效果。 2、编写第1章中的实例源文件,并在Microsoft Internet Explorer浏览器中进行测试。 3、调试一段JavaScript程序,找出其中的错误。 三、实验步骤 1、通过windows的文件管理器,在c盘下新建一个文件夹jsp_ex,用于保 存实验中的文件,如图1-1所示。 2、在windows中打开“记事本”,(也可以用其他编辑html文件的工具软 件,如Microsoft frontpage,Macromedia Dreamweaver等,编写例1-1的程序,然后将文件保存在C:\jsp_ex文件夹中。 3、用下述任意一种方法,在浏览器中显示,如图1-2。

A.在图1-1中双击“”文件名。 B.在图1-1中用鼠标右键单击“”,在打开的菜单列表中,如果有所需浏览器名就可以直接点击浏览器名。 C.现在windows中打开所需浏览器,然后按【ctrl】+【o】,在打开的对话框中找到文件。 4、再次编辑文件,将第21行中的“”改写为“”然后按第3步的操作, 得到如图1-3的效果,不能显示“上一次网页更新日期”,这时,通过浏览器的调试工具查找出出错的位置,修改后再次测试。 5、按1-2的步骤,将例1-1改写为“”和“”两个文件即通过外部javascript 文件和html文件一起完成网页的制作。 四、思考练习 1.为什么“上一次网页更新日期”在每一次打开都是同一个时间 2.请写出你在程序编写中出现的错误和改正方法,并分析。

JavaScript中按键事件的e.keyCode e.which e.charCode

JavaScript中按键事件的e.keyCodee.whiche.charCode 1、浏览器的按键事件 浏览器有3种按键事件——keydown,keypress和keyup,分别对应onkeydown、onkeypress和onkeyup3个事件句柄。 一个典型的按键会产生所有这三种事件,依次是keydown-->keypress-->keyup。[html]view plaincopyprint? 1. 2. 控制台输出: keydown keypress keyup 2、浏览器的兼容性

(1)FireFox、Opera、Chrome 事件对应的函数有一个隐藏的变量e,表示发生事件。 e有一个属性e.which指示哪个键被按下,给出该键的索引值(按键码)。 静态函数String.fromCharCode()可以把索引值(按键码)转化成该键对应的的字符。eg: [html]view plaincopyprint? 1. 2. FireFox、Opera、Chrome中输入:a 输出:按键码:97 字符:a (2)IE IE不需要e变量,window.event表示发生事件。 window.event有一个属性window.event.keyCode指示哪个键被按下,给出该键的索引值(按键码)。 静态函数String.fromCharCode()可以把索引值(按键码)转化成该键对应的的字符。eg: [html]view plaincopyprint?

JavaScript事件

我的记录(JavaScript事件)JavaScript 事件冒泡简介及应用实例 一、什么是事件冒泡 在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。 打个比方说:你在地方法院要上诉一件案子,如果地方没有处理此类案件的法院,地方相关部门会帮你继续往上级法院上诉,比如从市级到省级,直至到中央法院,最终使你的案件得以处理。 二、事件冒泡有什么作用 (1)事件冒泡允许多个操作被集中处理(把事件处理器添加到一个父级元素上,避免把事件处理器添加到多个子级元素上),它还可以让你在对象层的不同级别捕获事件。 【集中处理例子】

 
实验三

实验目的:常用函数的使用。 实验内容: 利用全局变量和函数,设计模拟幸运数字机游戏。设幸运数字为 8,每次 由计算机随机生成 3 个 1~9之间的随机数,当这 3 个随机数中有一个数字 为 8 时,就算赢了一次。 Ex050309.html

 
实验三

实验目的:常用函数的使用。 实验内容: 利用全局变量和函数,设计模拟幸运数字机游戏。设幸运数字为8,每次由计算机随机生成3个1~9之间的随机数,当这3个随机数中有一个数字为8时,就算赢了一次。 Ex050309.html varwin_rate=0; //赢率 varplay_times=0; //总次数 varwins=0; //赢的次数 varlast_digits; //上次数字串 varlast_win; //上次是否赢?