2012-02-06 93 views
1

我一直在玩JavaScript的原型繼承,並已被new關鍵字的行爲困惑。我不明白爲什麼繼承對象的[[prototype]]屬性指向Function.prototype而不是繼承對象的原型。考慮2個構造函數(如下圖):javascript原型繼承和'新'關鍵字

function Animal(name) { 
    this.name = name; 
} 

function Cat(name) { 
    Animal.call(this, name); 
} 

Cat.prototype = new Animal(); 

查詢的構造函數Cat的原型,我得到一些有趣的結果:

Cat.__proto__ === Animal.prototype; //returns false -- shouldn't this be true? 
Cat.__proto__ === Function.prototype; //returns true 
Cat.prototype instanceof Animal; //returns true, as expected 

我的理解是,Cat[[prototype]]應更新點到Animal.prototype當我們將它的原型屬性設置爲Animal的一個新實例時,應該本質上爲

  1. 創建一個新的對象基於Animal.prototype
  2. 內部設置Cat.[[prototype]]Animal的外部原型屬性?

我已經在Chrome和FF中試過這個,結果相同。是什麼賦予了?

而且,當我們分配Cat.prototypenew Animal(),應該Cat.prototype是什麼?即:

//if Cat.prototype = new Animal(); 
//then 
Cat.prototype === Animal.prototype; //get false. Should this be true? 
+1

使用此 - 「Cat.prototype = Object.create(Animal.prototype);' - 設置繼承。 – 2012-02-06 01:35:29

+0

是的,我知道「物體」。創造()',但目標是學習'準系統'原型繼承的方法。 'Object.create()'是我的下一步。 – 2012-02-06 01:45:22

+2

'X.prototype = new Y();'是有缺陷的,因爲'prototype'對象被分配給'Y'的新實例的屬性所污染。你想避免這種做法,並做它應該如何完成(通過'Object.create()')。 – 2012-02-06 02:09:09

回答

2
Cat.__proto__ === Animal.prototype; //returns false -- shouldn't this be true? 
Cat.__proto__ === Function.prototype; //returns true 

Cat構造是一個函數。因此,它繼承自Function.prototype,其繼承自Object.prototypeAnimal構造函數和所有其他函數對象也是如此。

僅僅因爲您分配給Cat.prototype不會更改Cat構造函數本身的繼承鏈接(繼承鏈接始終是不可變的)。

請注意,Cat實例不會從Cat繼承,而是從Cat.prototype繼承。因此,無論如何,您並不關心Cat構造函數的原型鏈接。

+0

+1。換句話說(也許更清楚,也許不是),實例繼承自其構造函數的內部Prototype。聲明的函數是'Function'的實例,所以它們繼承自'Function.prototype'(就像'Cat'一樣)。 Cat的實例(即由new Cat()創建的對象)將從Cat.prototype繼承,Cat.prototype在本例中是Animal的一個實例,所以它們也繼承自Animal.prototype。 – RobG 2012-02-06 02:37:55

+0

所以構造函數和對象在構造函數總是繼承自Function.prototype的意義上是不同的,而對象層次結構可以根據其父代在創建過程中的繼承層次而不同。但是,一旦聲明/實例化,對象和構造函數的內部[[[prototype]]層次結構保持不變,即不可變。它是否正確? – 2012-02-06 13:07:14

+0

@keyser_sozay一些更正:(1)構造函數*也是*對象。所以在你的比較中,你可能意味着函數對象和非函數對象。 (2)一個對象的繼承鏈接總是指向它的構造器的原型對象(例如'new X()'對象繼承自'X.prototype')。 ***是的,一旦創建了一個對象,就不可能改變(重定向)它的繼承鏈接。 – 2012-02-06 13:55:46

0

[[prototype]]屬性由Object擁有,而不是由Constructor函數擁有。 所以,在你的榜樣,你會發現,

Cat.prototype.__proto__ === Animal.prototype; //Return true 

通用說

Instance.__proto__ === Constructor.prototype; //Retrun true 

貓是一個構造函數,函數類型的實例,讓你看到這個結果

Cat.__proto__ === Function.prototype; //Return true 

我的英語太可怕了,但我希望我已經解釋了一些東西。 :-)