首页 > web前端 > js教程 > 正文

维护JS代码的三种方法

php中世界最好的语言
发布: 2018-06-04 10:48:55
原创
1661 人浏览过

这次给大家带来维护JS代码的三种方法,维护JS代码的注意事项有哪些,下面就是实战案例,一起来看一下。

维护。在其他语言中,考虑将已存在的对象作为库用来完成开发任务。在JS中,我们可以将已存在的对象视为一种背景,在这之上可以做任何事情。你应该把已存在的JS对象如一个使用工具函数库一样来对待。

不覆盖方法

不新增方法

不删除方法

当项目中只有你一个开发者时,因为你了解它们,对它们有预期,这些种类的修改很容易处理。当与一个团队一起在做一个大型的项目时,像这些情况的修改会导致大量的混乱,也会浪费很多时间。

不覆盖方法

在JS中,有史以来最糟糕的实践是覆盖一个非自己拥有的对象的方法,JS中覆盖一个已存在的方法是难以置信的容易。即使那个神圣的document.getElementById()方法也不例外,可以被轻而易举地覆盖。也许你看过类似下面的模式(这种做法也叫“函数劫持”):

// 不好的写法document._originalGetElementById = document.getElementById;document.getElementById = function (id) {  if (id === 'window') {    return window;
  } else {    return document._originalGetElementById(id);
  }
}
登录后复制

上例中,将一个原生方法document.getElementById()的“指针”保存在document._originalGetElementById中,以便后续使用。然后,document.getElementById()被一个新的方法覆盖了。新方法有时也会调用原始的方法,其中有一种情况不调用。这种“覆盖加可靠退化”的模式至少和覆盖原生方法一样不好,也许会更糟,因为document.getElementById()时而符合预期,时而不符合。 在一个大型的项目中,一个此类问题就会导致浪费大量时间和金钱。

不新增方法

在JS中为已存在的对象新增方法是很简单的。只需要创建一个函数赋值给一个已存在的对象的属性,使其成为方法即可。这种做法可以修改所有类型的对象。

// 不好的写法 - 在
DOM对象
上增加了方法document.sayImAwesome = function () {
  alert("You're awesome.");
}// 不好的写法 - 在原生对象上增加了方法Array.prototype.reverseSort = function () {  return this.sort().reverse();
}// 不好的写法 - 在库对象上增加了方法YUI.doSomething = function () {  // 代码}
登录后复制

几乎不可能阻止你为任何对象添加方法(ES5新增了三个方法可以做到,后面会介绍)。为非自己拥有的对象增加方法一个大问题,会导致命名冲突。因为一个对象此刻没有某个方法不代表它未来也没有。 更糟糕的是如果将来原生的方法和你的方法行为不一致,你将陷入一场代码维护的噩梦。

我们要从Prototype JS类库的发展历史中吸取教训。从修改各种各样的JS对象角度而言Prototype非常著名。它很随意地为DOM和原生的对象增加方法。实际上,库的大多数代码定义为扩展已存在的对象,而不是自己创建对象。Prototype的开发者将该库看作是对JS的补充。在小于1.6的版本中,Prototype实现了一个document.getElementsByClassName()方法。也许你认识该方法,因为在HTML5中是官方定义的,它标准化了Prototype的用法。

Prototype的document.getElementsByClassName()方法返回包含了指定CSS类名的元素的一个数组。Prototype在数组上也增加了一个方法,Array.prototype.each(),它在该数组上迭代并在每个元素上执行一个函数。这让开发者可以编写如下代码:

document.getElementsByClassName('selected').each(doSomething);
登录后复制

在HTML5标准化该方法和浏览器开始原生地实现之前,代码是没有问题的。当Prototype团队知道原生的document.getElementsByClassName()即将到来,所以他们增加了一些防守性的代码,如下:

if (!document.getElementsByClassName) {  document.getElementsByClassName = function (classes) {    // 非原生实现
  };
}
登录后复制

故Prototype只是在document.getElementsByClassName()不存在的时候定义它。这看上去好像问题就此解决了,但还有一个重要的事实是:HTML5的document.getElementsByClassName()不返回一个数组,所以each()方法根本不存在。原生的DOM方法使用了一个特殊化的集合类型称为NodeList。document.getElementsByClassName()返回一个NodeList来匹配其他的DOM方法的调用。

如果浏览器中原生实现了document.getElementsByClassName()方法,那么由于NodeList没有each()方法,无论是原生的或是Prototype增加的each()方法,在执行时都将引发一个JS错误。最后的结局是Prototype的用户不得不既要升级类库代码还要修改他们自己的代码,真是一场维护的噩梦。

从Prototype的错误中可以学到,你不可能精确预测JS将来会如何变化。标准已经进化了,它们经常会从诸如Prototype这样的库代码中获得一些线索来决定下一代标准的新功能。事实上,原生的Array.prototype.forEach()方法在ECMAScript5有定义,它与Prototype的each()方法行为非常类似。问题是你不知道官方的功能与原生会有什么样的不同,甚至是微小的区别也将导致很大的问题。

大多数JS库代码有一个插件机制,允许为代码库安全地新增一些功能。如果想修改,最佳最可维护的方式是创建一个插件。

不删除方法

删除JS方法和新增方法一样简单。当然,覆盖一个方法也是删除已存在的方法的一种方式。最简单的删除一个方法的方式就是给对应的名字赋值为null。

// 不好的写法 - 删除了DOM方法document.getElementById = null;
登录后复制

将一个方法设置为null,不管它以前是怎么定义的,现在它已经不能被调用到了。如果方法是在对象的实例上定义的(相对于对象的原型而言),也可以使用delete操作符来删除。

var person = {  name: 'Nicholas'};delete person.name;console.log(person.name); // undefined
登录后复制

上例中,从person对象中删除了name属性。delete操作符只能对实例的属性和方法起作用。如果在prototype的属性或方法上使用delete是不起作用的。例如:

// 不影响delete document.getElementById;console.log(document.getElementById('myelement')); // 仍然能工作
登录后复制

因为document.getElementById()是原型上的一个方法,使用delete是无法删除的。但是,仍然可以用对其赋值为null的方式来阻止被调用。

无需赘述,删除一个已存在对象的方法是糟糕的实践。不仅有依赖那个方法的开发者存在,而且使用该方法的代码有可能已经存在了。删除一个在用的方法会导致运行时错误。如果你的团队不应该使用某个方法,将其标识为“废弃”,可以用文档或者用静态代码分析器。删除一个方法绝对应该是最后的选择。

反之,不删除你拥有对象的方法实际上是比较好的实践。从库代码或原生对象上删除方法是非常难的事情,因为第三方代码正依赖于这些功能。在很多案例中,库代码和浏览器都会将有bug或不完整的方法保留很长一段时间,因为删除它们以后会在数不胜数的网站上导致错误。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

web开发中如何避免空比较

为什么web开发中需要避免使用全局变量

以上是维护JS代码的三种方法的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!