【譯】JavaScript中的對象和繼承

來源:互聯網
上載者:User

譯者註:這是一篇關於JavaScript的物件導向和繼承的文章,寫於1年前,作者循序漸進,對想學習JavaScript中物件導向的同學來說是很有協助的,因此試著翻譯一下,不妥之處,請指正。原文連結Objects and Inheritance in Javascript


雖然一些Javascript使用者可能永遠也不需要知道原型或物件導向語言的性質,但是那些來自傳統物件導向的語言的開發人員使用的時候會發現JavaScript的繼承模型非常的奇怪。而不同的JS架構提供了各自的方法來編寫類物件導向(class-like)的代碼,這使得JS的物件導向更加的難以理解。這樣帶來的結果是:

1、沒有一個標準的方法來實現物件導向。

2、JS物件導向的底層概念並沒有得到人們的熟知

原型繼承

原型繼承是一個非常簡單的概念,它的本質是:

1、對象a繼承自對象b,就說b是a的原型(prototype)。

2、a繼承了b的所有的屬性,即如果b.x的值為1,那麼a.x的值為1

3、a自身的屬性會重寫b中同名的屬性

讓我們在具體的代碼中看看效果,假設有一個John Smith和一個繼承自他的Jane。

1 var john = {firstName: 'John', lastName: 'Smith'};2 var jane = {firstName: 'Jane'};3 jane.__proto__ = john;

現在,我們稱john是jane的原型(prototype),jane繼承了john的所有的屬性

1 jane.lastName2 "Smith"//該屬性繼承自john

jane自身的屬性具有較高的優先順序,如下

1 jane.firstName;//該屬性覆寫了john中的firstName屬性2 "Jane"

如果在這之後給john添加一個屬性,jane也會動態繼承該屬性,如下所示

1 john.hair = 'brown'; //給john添加一個新屬性2 jane.hair;3 "brown"//結果表明jane繼承了新添加的屬性

現在,我們假設jane結婚了,因此有了一個新的姓(last name)

1 jane.lastName = 'Doe'

該屬性覆蓋了john當中的同名的屬性(lastName)

1 jane.lastName2 "Doe"

但是,如果我們現在刪除jane的lastName

1 delete jane.lastName

該屬性的值就會恢複為john的值

1 jane.lastName2 "Smith"

現在,jane也可以繼承自其它的對象。在這個鏈中可以有任意多個繼承,我們將它稱為原型鏈(prototype chain),實際上,john也有一個prototype屬性

1 john.__proto__;2 Object { }

在Firebug的控制台中,john.__proto__的值設為了Object{},但是Object{}代表著Object.prototype這個對象——所有對象的父類。

這就是對原型繼承的一個簡要描述。看起來還不錯,是吧?

但是,實際上,我們是不能用__proto__的。。。

告訴大家一個不好的訊息......

IE不支援__proto__屬性,實際上,__proto__並不是ECMAScript規範中的屬性,而且,Mozilla也打算在Firefox瀏覽器以後的的版本中去掉該屬性。

但是,這並不意味著__proto__屬性不存在。雖然在某些瀏覽器中無法直接存取到__proto__屬性,但是它還是以某種形式存在,我們還得和他打交道,只不過沒有那麼直接了。

類和繼承

因此,我們可以說,JavaScript沒有類

請記住:JavaScript中沒有類

那既然這樣,方法和繼承有事怎麼實現的呢?

通過原型(prototype)。在傳統的物件導向的語言中,方法是依賴於類的,而在JavaScript當中,方法是依賴於對象的原型的,並且,原型是和對象的構造器(constructor)綁定在一起的。

在JavaScript當中,函數起到了構造器(constructor)的作用。通過使用new運算子,你可以把一個函數當做建構函式(constructor)來用。下面的代碼展示了我們建立了一個Cat函數:

1 function Cat(name){  // <-這是一個常規的函數2     this.name = name   // this指向建立的對象3 }

以上代碼會自動建立一個Cat.prototype對象

1 Cat.prototype2 Cat { }

我們可用new操作符來建立Cat的一個執行個體

1 var garfield = new Cat('Garfield')   // 建立一個執行個體 - Cat函數充當了建構函式

現在,Cat.prototype對象成為了所有的通過new Cat()建立的對象的原型,例如:

1 garfield.__proto__ === Cat.prototype2 true //看到了嗎? `Cat.prototype` 現在是garfield對象的原型

現在,我們給Cat.prototype添加一個方法,添加之後,該方法可以被garfield訪問到

1 Cat.prototype.greet = function(){2     console.log('Meow, I am ' + this.name)3 }4 garfield.greet()5 "Meow, I am Garfield"

其他的Cat的執行個體也可以訪問到

1 var felix = new Cat('Felix')2 felix.greet()3 "Meow, I am Felix"

因此,在JavaScript中,方法是依賴於對象的原型(prototype)而存在的。

實際上,我們也可以為garfield添加方法,它會覆寫Cat.prototype中的同名方法,如下所示:

1 garfield.greet = function(){2     console.log("What's new?");3 };4 garfield.greet();5 "What's new?"

但這並不會影響到其他的對象

1 felix.greet();2 "Meow, I am Felix"

因此,JavaScript中,方法可以直接和一個對象關聯,可以和對象的原型關聯,也可以和對象的任意一個父輩對象關聯,即,可以和原型鏈(prototype chain)的任意一環關聯。繼承也就是這樣實現的。

要建立一個二級原型鏈(prototype chain),我們首先需要建立另一個建構函式(constructor),叫Animal如何?

1 function Animal(){2 }

接下來,我們需要將Cat.prototype的原型指向一個Animal的對象,這樣一來,Cat的執行個體就會繼承所有的Animal的方法。因此,我們將Cat.prototype的值設定為Animal的執行個體,如下所示:

1 Cat.prototype = new Animal();

 除此之外,我們還要告訴新的Cat.prototype,它實際上是Cat的一個執行個體:

1 Cat.prototype.constructor = Cat    // 讓`Cat.prototype` 知道它是Cat的一個執行個體

雖然這樣做的目的主要是為了類之間的層次關係,但通常還是有必要這樣做的。

現在,既然繼承自Animal.prototype和Cat.prototype的對象是屬於動物類,那麼所有Cat的執行個體也間接的繼承自Animal.prototype。如果我們給Animal.prototype添加一個新方法,那麼,所有的Cat的執行個體也能夠訪問到該方法。

1 Animal.prototype.breed = function(){2     console.log('Making a new animal!');3     return new this.constructor();4 };5 var kitty = garfield.breed();6 Making a new animal!

通過上面的代碼我們就實現了繼承,簡單吧。

結語

雖然JavaScript中基於原型的繼承很怪並且需要花一些時間才能習慣,但是他的核心思想是很簡單的。只要你真正理解了這些本質上的概念,你就會有信心在這些良莠不齊的代碼中駕馭JavaScript的OO。(完)^_^

相關文章

聯繫我們

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