自由的脚本与重构的详细介绍
自由的脚本与重构的详细介绍
自由的脚本 与 重构
关键字:脚本、重构
想想,该写点什么像样的东西了,今天忽然在论坛里看到了一个帖子,给了一个答案,几看都不是很爽,于是就试着重构了几下,写写心得。
问题是这样的:http://community.csdn.net/Expert/topic/3178/3178153.xml?temp=.261532
求一个正则表达式,去除网页上name为yyy的img元素
我急用一个正则表达式,去除网页上name为yyy的img元素,其中yyy是一个变量,我想作成一个函数的形式
funciton qichu(img_name){
//在这里删除name属性为img_name的img元素,注意img_name是一个字符串变量
}
关于为什么不用正则式的原因:
我知道,正则表达式的替换是非常方便的,但是对于HTML XML这类标记性文档,通过DOM的API来访问应该比直接的字符串操作要正统,安全(就是说可以保证ML的well formed)。
var count = document.all.tags("IMG").length;
并且,看这里,这里已经提供了替换其他标签的能力。
在贴出代码以前先谈谈对重构的看法:重构是一个概念,跨越了语言的界限,JAVA需要重构,C#需要,C++需要,Scripting同样需要;重构是把垃圾变成艺术品一种手段,我们每天在制造各种各样的垃圾(也许你往往一蹴而就,不制造垃圾,但是这是理想),目的只是为了让程序能够工作,在这些垃圾中,我们挑选出有价值(最基本的价值,是否有人为这种改进付钱,既是价值,当然了,好像有点违背职业道德,但是往往我们需要面对现实)的东西,将它变成艺术品,有人说编程是艺术,但是注意,并不是所有的从事艺术的人都可以成为艺术家,都能够做出艺术品。
同样,由于我写的是自由的脚本,所以也说说脚本:我说的脚本指Javascript(对于其他脚本,可以称作脚本,自然要有比程序语言优越之处),脚本是一种自由的、灵活的、轻量级的编程语言,在javascript中很多特性都是JAVA、C#等所不能及的,例如:动态的类型绑定(不是很确切,弱类型)、动态的添加成员等,同时脚本又具有基本的面向对象的特征,不多说了,看正题。
开始:提出解决思路
由于问题是按照元素的name来区分的,又要取得多个,所以不用document.all.yyy来取得collection了,因为如果这样的话需要判断name为yyy的数量如果只有一个,是不会形成collection的(IE和脚本在处理网页元素上的特性吧,算是一个脚本的魅力),判断过程会使程序变得难以理解,所以采用取得所有IMG元素的方法(并非只有一种方法),为了防止collection元素变动造成循环错误,先取得一个循环次数值,定义一个临时数组,存放所有名为 yyy 的 IMG 的元素实例,遍历数组清除目标 IMG 元素,于是有了下面的代码。
var count = document.all.tags("IMG").length;
var tmparray = new Array();
for (var i=0; i<count; i++)
{
if (document.all.tags("IMG")[i].name == "yyy")
tmparray[tmparray.length] = document.all.tags("IMG")[i];
}
for (var i=0; i<tmparray.length; i++)
{
tmparray[i].outerHTML = "";
}
tmparray = null;
进行第一次重构:Extract Method
提取出函数,并将document.body动态(script的魅力)添加一个方法,方法所作操作为函数中内容,由于document.body已经生成实例了,所以没有必要对prototype操作,直接为实例添加就可以了。
注意:前后两个removeElementsWithName的意义是不同的,前一个表示了document.body的一个方法,后一个则是局部的一个函数。
//
// 第一次重构
//
document.body.removeElementsWithName = function removeElementsWithName( elementTag, elementName )
{
var count = document.all.tags(elementTag).length;
var tmparray = new Array();
for (var i=0; i<count; i++)
{
if (document.all.tags(elementTag)[i].name == elementName)
tmparray[tmparray.length] = document.all.tags(elementTag)[i];
}
for (var i=0; i<tmparray.length; i++)
{
tmparray[i].outerHTML = "";
}
tmparray = null;
}
document.body.removeElementsWithName( "IMG", "yyy" );
进行第二次重构:规范第一次重构提取后的代码
第一次着重于封装,将函数封装入对象(类),由于removeElementsByName(指后一个局部函数)现在是一个对象的方法,所以,对脚本内的访问已经没有任何意义,去掉名字,使用匿名函数(脚本的魅力)代替,并在函数内部使用this指代document,并把方法由document.body转移给document,使得方法更具有普遍性,并更改函数名With为By。
//
// 第二次重构
//
document.removeElementsByName = function ( elementTag, elementName )
{
var count = this.all.tags(elementTag).length;
var tmparray = new Array();
for (var i=0; i<count; i++)
{
if (this.all.tags(elementTag)[i].name == elementName)
tmparray[tmparray.length] = this.all.tags(elementTag)[i];
}
for (var i=0; i<tmparray.length; i++)
{
tmparray[i].outerHTML = "";
}
tmparray = null;
}
document.removeElementsByName( "IMG", "yyy" );
完成:实际并没完
至此两次重构已经完成,但是,可以看到,代码里依然有smells,比如removeElementsByName,这个长方法名,暂且放他一马吧。