首頁 >web前端 >js教程 >維護JS程式碼的三種方法

維護JS程式碼的三種方法

php中世界最好的语言
php中世界最好的语言原創
2018-06-04 10:45:381695瀏覽

這次帶給大家維護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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn