From:http://www.ajaxwing.com/index.php?id=2
一,背景
回顧一下編程語言的發展,不難發現這是一個不斷封裝的過程:從最開始的匯編語言,到面向過程語言,然后到面向對象語言,再到具備面向對象特性的腳本語言,一層一層封裝,一步一步減輕程序員的負擔,逐漸提高編寫程序的效率。這篇文章是關于 JavaScript 的,所以我們先來了解一下 JavaScript 是一種怎樣的語言。到目前為止,JavaScript 是一種不完全支持面向對象特性的腳本語言。之所以這樣說是因為 JavaScript 的確支持對象的概念,在程序中我們看到都是對象,可是 Javascipt 并不支持類的封裝和繼承。曾經有過 C++、Java或者 php、python 編程經驗的讀者都會知道,這些語言允許我們使用類來設計對象,并且這些類是可繼承的。JavaScript 的確支持自定義對象和繼承,不過使用的是另外一種方式:prototype(中文譯作:原型)。用過 JavaScript 的或者讀過《設計模式》的讀者都會了解這種技術,描述如下:
每個對象都包含一個 prototype 對象,當向對象查詢一個屬性或者請求一個方法的時候,運行環境會先在當前對象中查找,如果查找失敗則查找其 prototype 對象。注意 prototype 也是一個對象,于是這種查找過程同樣適用在對象的 prototype 對象中,直到當前對象的 prototpye 為空。
在 JavaScript 中,對象的 prototype 在運行期是不可見的,只能在定義對象的構造函數時,創建對象之前設定。下面的用法都是錯誤的:
o2.prototype = o1;
/*
這時只定義了 o2 的一個名為“prototype”的屬性,
并沒有將 o1 設為 o2 的 prototype。
*/
// ---------------
f2 = function(){};
o2 = new f2;
f2.prototype = o1;
/*
這時 o1 并沒有成為 o2 的 prototype,
因為 o2 在 f2 設定 prototype 之前已經被創建。
*/
// ---------------
f1 = function(){};
f2 = function(){};
o1 = new f1;
f2.prototype = o1;
o2 = new f2;
/*
同樣,這時 o1 并不是 o2 的 prototype,
因為 JavaScript 不允許構造函數的 prototype 對象被其它變量直接引用。
*/
正確的用法應該是:
f1 = function(){};
f2 = function(){};
f2.prototype = new f1;
o2 = new f2;
從上面的例子可以看出:如果你想讓構造函數 F2 繼承另外一個構造函數 F1 所定義的屬性和方法,那么你必須先創建一個 F1 的實例對象,并立刻將其設為 F2 的 prototype。于是你會發現使用 prototype 這種繼承方法實際上是不鼓勵使用繼承:一方面是由于 JavaScript 被設計成一種嵌入式腳本語言,比方說嵌入到瀏覽器中,用它編寫的應用一般不會很大很復雜,不需要用到繼承;另一方面如果繼承得比較深,prototype 鏈就會比較長,用在查找對象屬性和方法的時間就會變長,降低程序的整體運行效率。
新聞熱點
疑難解答