2016-02-02 81 views
0

我知道這個問題可能在其他Q & A(如How does JavaScript .prototype work?問題)中被觸及,但是(我希望!)這是一個更具體的問題,爲什麼在某些情況下使用.prototype有些「覆蓋」有些則沒有。爲了幫助說明(從ejohn.org爲例):爲什麼一些原型函數覆蓋工作而另一些不覆蓋?

function Ninja() { 
    this.swingSword = function() { return true; }; 
}; 
Ninja.prototype.swingSword = function() { return false; }; 

var my_ninja = new Ninja(); 
alert(my_ninja.swingSword()); 

上面的例子會提醒「真」,根據ejohn.org網站的例子,說明這是有道理的,但隨後這個作品也完全矛盾根據上面的代碼,我認爲是不可能的:

var _send = XMLHttpRequest.prototype.send; 
XMLHttpRequest.prototype.send = function(){ 
    alert("Overridden!"); 
    _send.apply(this, arguments); 
}; 

兩者如何都能成立?一個準確地不被覆蓋,另一個是?據我所知,它們都是對象,並且swingSwordsend函數都是函數?那麼我們如何覆蓋XMLHttpRequestsend函數,而不是NinjaswingSword函數呢?

預先感謝您的任何見解和幫助!

回答

1

在JavaScript中沒有重寫的真正概念。當使用new實例化時,原型對象僅在新對象中引用(如__proto__),而對對象中不存在的屬性的任何訪問都將被路由到原型對象。仍然調用「構造函數」函數,以便在調用者使用它之前有機會修改新對象。如你所知,在構造函數中,新對象被引用爲this。在你的情況下,你實際上會將swingSword函數添加到之前不存在的新對象中。如果沒有,則對swingSword屬性(函數)的所有訪問都將回退到原型。換句話說,你「覆蓋」原型功能,而不是相反!

確保您瞭解執行順序。僅僅因爲你在定義構造函數之後在原型上設置函數並不意味着它優先。實際上,構造函數在使用new時執行。

現在應該清楚爲什麼第二種方案有效; XHR的構造函數不會創建發送函數,因此始終會使用原型對象上的函數。既然你把它取代原來的原型,你基本上「覆蓋」了它。順便說一下,這就是爲什麼原始文件保存在_send變量中;否則您將無法引用它或恢復它!

+0

哦,我明白了!所以在XHR構造函數中沒有創建'send'函數!一切都變得更有意義了,謝謝!那麼接下來是一個小的分拆問題,那麼如何知道可用的函數是否是構造函數創建的或以其他方式創建的呢? –

+1

@ChrisKempen好問題!幸運的是,它有一個簡單的答案:使用['hasOwnProperty'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty)。 – tne

+0

啊啊,謝謝!我的頭痛終於消散了! +1 –