在JavaScript中實現繼承

來源:互聯網
上載者:User
javascript|繼承 JavaScript指令碼語言是一種功能強大的物件導向的語言。本文描述了如何在JavaScript中實現繼承。

Prototype

JavaScript沒有實作類別繼承,但可以通過prototype實現。每個JavaScript類中都包含一個prototype對象,當訪問一個對象的屬性和方法時,它首先從當前對象尋找,如果該屬性在JavaScript類定義,則直接存取;否則,從類的prototype對象中尋找,如果找到則直接存取,否則從prototype的prototype對象中尋找,以此類推,直接prototype對象為空白。換句話說,當前對象繼承了它所在類的prototype的所有屬性和方法。

但是,prototype對象是屬於一個類的,而一個類又可以建立多個對象,因而,訪問繼承來的屬性時讀取和寫入是有區別的。當讀取一個繼承的屬性時,按上面所述的步驟尋找屬性;當寫入一個屬性時,則從prototype中複製資料到當前對象;再次讀取時,訪問的是當前對象的屬性。對於方法不存在這種問題。

實現繼承

JavaScript類的prototype預設類型是Object類,所以可以說,JavaScript中所有類都從Object類繼承。我們可以修改一個類的prototype屬性,使它指向一個其它對象,從而實現繼承。實現繼承通常有兩種方式:

  • 修改一個類的prototype屬性,使其指向一個父類對象
  • 修改一個類的prototype對象的constructor屬性,為其指定一個父類的建構函式

兩種實現方法基本相同,但存在一些差別。代碼清單1採用第一種方式,代碼清單2採用第二種方式。

//定義基類Shapefunction Shape(x, y) {this.x = x;this.y = y;this.fromOrigin = function() { //定義方法return Math.sqrt(this.x * this.x + this.y * this.y);}}//可以採用這種方式/*Shape.prototype.fromOrigin = function() {return Math.sqrt(this.x * this.x + this.y * this.y);}*///定義子類Circlefunction Circle(x, y, r) {Circle.prototype.constructor(x, y); //調用父類建構函式this.r = r;}Circle.prototype = new Shape(); //綁定父物件//測試var c = new Circle(5, 5, 10);print(c);c.x = 3; //修改屬性c.y = 4;print(c);//列印function print(c) {document.write("Circle.prototype.x=" + Circle.prototype.x, "<br/>");document.write("Circle.prototype.y=" + Circle.prototype.y, "<br/>");document.write("c.x=" + c.x, "<br/>");document.write("c.y=" + c.y, "<br/>");document.write("c.r=" + c.r, "<br/>");document.write("c.fromOrigin()="+ c.fromOrigin(), "<br/>");}清單1:修改一個類的prototype屬性

輸出結果;

Circle.prototype.x=5Circle.prototype.y=5c.x=5c.y=5c.r=10c.fromOrigin()=7.0710678118654755Circle.prototype.x=5Circle.prototype.y=5c.x=3c.y=4c.r=10c.fromOrigin()=5

上面的代碼中,通過Circle.prototype = new Shape(); 綁定父物件,Circle對象包含了一個Shape所有的屬性和方法。

第一段輸出時,我們建立了一個Circle對象,在Circle的建構函式中調用父類Shape的建構函式,從而初始化了Shape中的x、y。當訪問c.x時,實際訪問的Circle.prototype引用的Shape對象的x。

第二段輸出時,我們修改了Circle對象的x和y,此時將Circle.prototype引用的Shape對象的x和y複製到Circle對象中,對Circle對象的修改不影響Circle.prototype引用的Shape對象。

fromOrigin方法既可以在Shape的建構函式中指定,也可以在Shape.prototype中指定。

//定義基類Shapefunction Shape(x, y) {this.x = x;this.y = y;this.fromOrigin = function() { //定義方法return Math.sqrt(this.x * this.x + this.y * this.y);}}//不能採用這種方式/*Shape.prototype.fromOrigin = function() {return Math.sqrt(this.x * this.x + this.y * this.y);}*///定義子類Circlefunction Circle(x, y, r) {Circle.prototype.constructor(x, y); //調用父類建構函式this.r = r;}Circle.prototype.constructor = Shape; //綁定prototype的建構函式為Shape(x, y)//測試var c = new Circle(5, 5, 10);print(c);c.x = 3; //修改屬性c.y = 4;print(c);//列印function print(c) {document.write("Circle.prototype.x=" + Circle.prototype.x, "<br/>");document.write("Circle.prototype.y=" + Circle.prototype.y, "<br/>");document.write("c.x=" + c.x, "<br/>");document.write("c.y=" + c.y, "<br/>");document.write("c.r=" + c.r, "<br/>");document.write("c.fromOrigin()="+ c.fromOrigin(), "<br/>");//document.write(Circle.prototype instanceof Object);}清單2:修改一個類的prototype對象的constructor屬性

清單2的輸出結果與清單1的輸出結果相同。

上面的代碼中,通過Circle.prototype.constructor = Shape; 綁定prototype的建構函式為Shape(x, y)。

fromOrigin方法只能在Shape的建構函式中指定,不可以在Shape.prototype中指定。原因是Circle.prototype.constructor = Shape;只指定的Circle.prototype的建構函式,Circle的prototype對象的類型沒有改變,仍然是Object類型,所以在Shape.prototype綁定的方法對Circle不可見。

結論

JavaScript是一種物件導向的語言,雖然表面上看起來不是很明顯(其中的頂級函數屬於Global對象)。我們可以通過JavaScript類的prototype來實現繼承,文中提到兩種方法以及它們的細微差別。

參考資料

David Flanagan, JavaScript: The Definitive Guide, 4th Edition, O'Reilly, 2001。



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.