談JavaScript的繼承

來源:互聯網
上載者:User

標籤:技術   引用   add   產生   對象引用   app   方式   研究   cells   

最近在忙前端的工作,因為之前做.net和php的開發比較多,前端開發喜歡把庫拿來就用,幾次事實證明,不懂原理,連改代碼也改不好,所以還是下定決心研究下JavaScript的幾個技術痛點。

0x1.JavaScript的對象和建構函式

定義一個JavaScript對象可以這麼定義

12345678910 var a = {    x : 1,    y : 2,    add : function () {        return this.x + this.y;    },    mul : function () {        return this.x * this.y;    }}

這樣,你就定義了一個變數a,這個變數除了有x和y兩個公有成員外,還有兩個add和mul兩個函數(公有方法)。但是這樣的定義方法的缺點有2條:

1.批量產生對象很不方便,如果你var b=a;那麼你每次修改b的成員,都會同時改掉a的成員,因為JavaScript的引用機制

2.如果每次產生對象需要自訂一些成員,都要寫出相應的賦值操作,增加程式碼數。

所以,在定義一個JavaScript對象之前,我們可以先定義一個建構函式。

12345678910 function A(x, y) {    this.x = x;    this.y = y;    this.add = function () {        return this.x + this.y;    }    this.mul = function () {        return this.x * this.y;    }}

然後,定義一個對象

1 a = new A(1, 2);

上面這句代碼看起來簡單,但是要和C++等物件導向的語言做個區分,A並不是嚴格意義上“類”的概念,因為JavaScript是沒有類的,只是調用了建構函式而已。

現在問題來了,我們怎麼實現繼承?C++把封裝,繼承,多態這三個物件導向的特徵實現得清清楚楚。但是對於JavaScript這樣一個比較浪的語言,沒有一個很嚴格的繼承機制,而是採用以下幾種方式來類比。

0x2.JavaScript的prototype

為了能夠講清後面的apply或call函數,這裡先引入prototype。prototype是只有Function才有的。

要用好繼承,首先要明白為什麼要設計繼承這個東西?無非就是“把公用的部分”提取出來,實現代碼複用。

所以在JavaScript裡,也是把公用部分放在Function的prototype裡。

我們來比較兩個用prototype來實現繼承的例子

123456789101112131415161718 function A(x, y) {    this.x = x;    this.y = y;    this.add = function () {        return this.x + this.y;    }    this.mul = function () {        return this.x * this.y;    }}function B(x,y){     }B.prototype=new A(1,2);console.log(new B(3,4).add());  //3

這個例子中,子類的prototype指向一個A類對象

我們再實現一個B繼承A的例子:

12345678910111213141516171819202122 function A() {     }A.prototype = {    x : 1,    y : 2,    add : function () {        return this.x + this.y;    },    mul : function () {        return this.x * this.y;    }}A.prototype.constructor=A;function B(){     }B.prototype=A.prototype;B.prototype.constructor=B;

B的prototype對象引用了A的prototype對象,因為是引用,所以如果修改了B的prototype對象,A的prototype對象也隨之修改,因為本質上他們都指向一塊記憶體。所以每次改動B類型的prototype都要手動將constructor改回,防止錯亂。相比兩個例子,上一個例子因為沒有引用,所以不會發生這個問題。

建立一個B類型的對象

1 b=new B();

b對象具有A類型的一切成員

1 console.log(b.add());    //3

因為每個prototype對象都有兩個重要成員:constructor和_proto_,constructor本質上是一個函數指標,所以B.prototype=A.prototype執行後,覆蓋掉了constructor,所以後面要讓constructor重新指向B類型的建構函式。

0x3.JavaScript的建構函式綁定

在定義完一個A類型的建構函式後,再定義一個B類型,然後在B類型建構函式內部,“嵌入執行”A類型的建構函式。

1234567891011121314151617 function A(x, y) {    this.x = x;    this.y = y;    this.add = function () {        return this.x + this.y;    }    this.mul = function () {        return this.x * this.y;    }}function B(x, y, z) {    A.apply(this, arguments);    this.z = z;}console.log(new B(1,2,3));

apply函數和call函數基本一樣,可以在B類型建構函式內部執行A類型建構函式。同時也可以繼承A的所有成員。

顯示結果:

這裡給個公式:在B建構函式裡寫A.apply(this),可以讓B構造出來的對象可以擁有A建構函式裡的所有成員。

談到apply和call,還可以實現多重繼承

1234567891011121314151617181920 function IA(){    this.walk=function(){        console.log("walk");    }}function IB(){    this.run=function(){        console.log("run");    }}function Person(){    IA.apply(this);    IB.apply(this);}var p=new Person();p.walk();  //walk       p.run();  //run

 

談JavaScript的繼承

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.