為什么要做A.prototype.constructor=A這樣的修正?
var currentBlogApp = 'SheilaSun', cb_enable_mathjax=false;var isLogined=false;
問題
雖然看過這篇博文JavaScript
prototype
之后對原型理解不再那么模糊了,但是依然還有很多理解不甚透徹的地方。比如,今天看到一個原型式繼承的例子,又有些困惑,于是找了些帖子看看,有了一些自己的理解,貼在這里,希望理解不對的地方大家可以幫我指出來,多謝了!
先看一段代碼:
function Person(){
console.log("in 'Person'");
}
function Woman(){
console.log("in 'Woman'");
}
var woman=new Woman();//in 'Woman'
woman.constructor;//function Woman(){console.log("in 'woman'");}
var person=new Person();//in 'Person'
person.constructor;//function Person(){console.log("in 'person'");}
以上定義了兩個function,各自實例化出一個對象后,在console中查看它們的constructor,一切正常。目前兩個function之間還沒有任何關系,下面用prototype讓它們之間掛鉤。設置Woman類的prototype是Person類,這個時候再來查看constructor的情況。
function Person(){
console.log("in 'Person'");
}
function Woman(){
console.log("in 'Woman'");
}
Woman.prototype=new Person();
var woman=new Woman();//in 'Woman'
/**constructor指向的是Person函數**/
woman.constructor;//function Person(){console.log("in 'person'");}
var person=new Person();//in 'Person'
person.constructor;//function Person(){console.log("in 'person'");}
可以看到woman的constructor指向了Person函數,這是為什么呢?
我的理解
我們知道,每個函數都有默認的prototype,這個prototype.constructor默認指向的就是這個函數本身。在未給Woman指定Person作為原型之前,Woman.prototype.constructor或者woman.proto
.constructor指向的就是Woman函數。但是當這樣做之后:
Woman.prototype=new Person();
Woman函數的prototype被覆蓋成了一個Person對象。我們知道,constructor始終指向的是創建本身的構造函數,因此Woman.prototype.constructor自然就指向了創建Woman.prototype這個Person對象的函數,也就是Person函數。這樣一來,woman對象的constructor指向就不對了,因此在網上大多關于原型繼承的帖子里都會建議我們做這樣的修改:
Woman.prototype.constructor=Woman;
var woman=new Woman();//in 'Woman'
woman.constructor;//function Woman(){console.log("in 'woman'");}
這樣修正以后,constructor的指向就正確了。但是,為什么要這樣修正呢?不修正會有什么后果呢?
為何要做A.prototype.constructor=A這樣的修正?
這是我最困惑的地方,因為我試驗后發現,就算不做這樣的修正,new
Woman()的時候也不會有什么問題,雖然我還不理解JS是如何做到的,但是它確實找到了正確的構造函數去做實例化。最后我在stackoverflow上找到了一個回答What
it the significance of the Javascript constructor property?
,里面提到:
The constructor property makes absolutely no practical difference to anything
internally. It's only any use if your code explicitly uses it. For example, you
may decide you need each of your objects to have a reference to the actual
constructor function that created it; if so, you'll need to set the constructor
property explicitly when you set up inheritance by assigning an object to a
constructor function's prototype property, as in your example.
所以,即使不做這樣的修正也不會有什么影響,它主要防止一種情況下出錯,就是你顯式地去使用構造函數。比如,我并不知道woman是由哪個函數實例化出來的,但是我想clone一個,這時就可以這樣:
var woman = new Woman();
...
...
...
var woman1 = woman.constructor();
?