JavaScript面向對象之二(構造函數繼承)

學習一波阮一峯的博客 戳這裏javascript

博客中是本身的理解,以及對大佬描述不清楚的地方進行了修正,也算是本身的一個再(xiao)產(tu)出(cao)吧html

上一篇:JavaScript面向對象之一(封裝)java

構造函數進行繼承


先來看個簡單的:bash

function Animal(){
    this.type = 'animal;'
}

function Cat(name, color){
    this.name = name
    this.color = color
    //這裏用call,我的以爲更好些
    Animall.call(this)
}

var cat = new Cat('po', 'orange')
console.log(cat.type) //animal
複製代碼

建立了一個Animal和Cat構造函數,而後在Cat裏面調用Animal的構造函數,在將Cat實例化,就能夠訪問到Animal的屬性了。 這個例子顯然有問題,放在第一個就是用來找茬的。函數

什麼問題呢?假如我想使用在Animal上的公共方法,像這樣Animal.prototype.eat = function(){ console.log('animal eat') },用cat.eat()是訪問不到的。post

爲何呢?由於咱們Cat和Animal的原型根本就沒有關聯起來呀。你看看我們上面的代碼,那個地方關聯過?學習

使用原型進行繼承


那下面咱們就將二者的原型關聯起來試試看ui

function Animal(){
    this.type = 'animal;'
}
Animal.prototype.eat = function(){ console.log('animal eat') }

function Cat(name, color){
    this.name = name
    this.color = color
}

Cat.prototype = new Animal()

var cat = new Cat('po', 'orange')
console.log(cat.type) //animal
console.log(cat.eat()) //animal eat
複製代碼

這種方法好!能夠拿到屬性和方法,一箭雙鵰。可是,這裏有個陷阱(keng)!!!Cat.prototype = new Animal()以後,咱們的Cat.prototype裏面的全部方法都消失了!這是怎麼回事?由於new,new作了四件事,這裏再次回顧一下:this

var temp = {}
temp.__proto__ = Animal.prototype
Animal.call(temp)
return temp
複製代碼

看到了嗎?new會使用一個空對象而且將其返回。這樣一來咱們的Cat.prototype就被清空了(包括自身的constructor)。因此咱們須要本身多作一件事Cat.prototype.constructor = Catspa

若是咱們不這樣作,那麼Cat.prototype的構造函數會是什麼?咱們在去看看new作的第二件事,這個空對象指向了Animal.prototype,因此Cat.prototype自身若是沒有constructor屬性的話就會去Animal.prototype上面去找。Cat.prototype.constructor === Animal //true

因此,若是咱們替換了prototype,須要手動去糾正它。

直接繼承prototype


既然上面這種方法有坑,並且的的確確讓你很容易漏掉,那咱們改進一下:

function Animal(){}
Animal.prototype.eat = function(){ console.log('animal eat') }

Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat

var cat = new Cat('po', 'orange')
console.log(cat.eat()) //animal eat
複製代碼

既然咱們想從Animal.prototype上面那東西,直接從上面拿不就好了?並且我還機智的填了上面會出現的坑。同時結果也是我想要的。

可是!!咱們的Cat.prototype和Animal.prototype指向的是同一個原型,這會致使我在Cat.prototype上作了什麼事,會同時發生在Animal.prototype上。這是爲何呢?MDZZ,這兩個就是同一個東西呀,原型是堆中一塊內存,Cat和Animal都指向這塊內存,操做的是同一個東西,怎麼會不影響?

與此同時,自覺得聰明的填坑Cat.prototype.constructor = Cat,此時的Cat和Animal的原型是同一個,修改了constructor以後,致使Animal的constructor變成了Cat。這種方法果斷PASS。。。

利用空對象做爲中介


var F = function(){}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat
複製代碼

咱們使用中間對象進行過分,巧妙的將Cat.prototype和Animal.prototype解耦,這樣就不會出現問題了。仔細觀察會發現這個和new作的事情有殊途同歸之處。

咱們進行封裝一下在使用

function extend(Child, Parent) {
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.uber = Parent.prototype;
}

extend(Cat,Animal);
var cat1 = new Cat('po' 'orange');
alert(cat1.eat()); // animal eat
複製代碼

這裏Child.uber = Parent.prototype的意思相似於__proto__

拷貝繼承


這裏還有一種簡單粗暴的方式

function extend2(Child, Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
        c[i] = p[i];
    }
    c.uber = p;
}

function Animal(){}
Animal.prototype.eat = function(){ console.log('animal eat') }

extend2(Cat, Animal);
var cat1 = new Cat('po' 'orange');
alert(cat1.eat()); // animal eat
複製代碼

直接遍歷父類的原型,一個個複製到子類原型上便可。

感慨一下,大佬仍是大佬呀。。。

相關文章
相關標籤/搜索