2011-06-08 31 views
13

可能重複:
Use of 'prototype' vs. 'this' in Javascript?添加方法,以自定義對象在Javascript

我去不同的網站,但無法理解添加方法自定義對象的下列方式之間的區別:

方法1:

function circle(radius){ 
    this.radius = radius; 
    this.area = function(){ return 3.14*this.radius*this.radius;} 
} 

方法2:

function circle(radius){ 
    this.radius = radius; 
} 
circle.prototype.area = function(){ return 3.14*this.radius*this.radius; } 

是否有任何性能或設計問題的方法之一,已經和其他不?

+0

在[使用的「原型」與「本」的可能重複Javascript的](http://stackoverflow.com/questions/310870/use-of-prototype-vs-this-in-javascript)和[原型與不,有什麼好處?](http://stackoverflow.com/questions/1319325/prototype-vs-not-what-are-benefits)和[使用原型的優勢與直接定義方法的直接關係在構造?](http://stackoverflow.com/questions/4508313/advantages-of-using-prototype-vs-defining-methods-straight-in-the-constructor)和其他人可能... – 2011-06-08 08:44:03

+0

謝謝@Felix ...抱歉重新發布它... – 2011-06-08 08:54:17

+0

這是[鏈接](http://www.packtpub.com/article/using-prototype-property-in-javascript),詳細討論。 – 2011-06-08 09:48:55

回答

12

這裏看出區別的一種方法:

var circle1 = circle(1); 
var circle2 = circle(1); 
alert(circle1.area == circle2.area); 

對於方法一,你會看到false而方法2得到的true。這是因爲在第一種情況下,您爲每個創建的對象分配一個新的閉包函數,但兩個對象的功能不同,即使兩者都執行相同的操作。在第二種情況下,對象與其area方法共享相同的原型對象,該方法在兩種情況下當然是相同的。

通常方法2是優選的有以下幾個原因:

  1. 對象的創建速度更快,因爲只有自定義屬性需要被初始化。
  2. 您不會浪費內存來實例化同一事物的多個副本。
  3. 通過調用Object.hasOwnProperty可以輕鬆找出哪些對象屬性具有自定義值。

還有一些缺點要記住。

  1. 即使您從不創建任何對象,您也總是花時間設置原型。
  2. 屬性訪問速度稍慢,因爲JavaScript引擎需要先檢查對象屬性,然後再檢查原型對象的屬性(現代JavaScript引擎對此進行了優化)。
  3. 在原型上放置對象或數組時有一個共同的陷阱,它們將在所有對象實例之間共享。

下面是常見的錯誤的例子:

function NumberCollection() 
{ 
} 
NumberCollection.prototype = { 
    numbers: [], 
    sum: function() 
    { 
     var result = 0; 
     for (var i = 0; i < this.numbers.length; i++) 
      result += this.numbers[i]; 
     return result; 
    } 
} 

var c1 = new NumberCollection(); 
c1.numbers.push(5); 
alert(c1.sum()); // Shows 5 
var c2 = new NumberCollection(); 
c2.numbers.push(6); 
alert(c2.sum()); // Oops, shows 11 because c1.numbers and c2.numbers is the same 

這裏正確的做法是:

function NumberCollection() 
{ 
    this.numbers = []; 
} 
NumberCollection.prototype = { 
    numbers: null, 
    sum: function() 
    { 
     var result = 0; 
     for (var i = 0; i < this.numbers.length; i++) 
      result += this.numbers[i]; 
     return result; 
    } 
} 
+1

感謝您的詳細解釋......您的意思是說,所有實例之間共享的函數必須使用原型屬性進行聲明,並且必須在對象中聲明屬性。 – 2011-06-08 09:15:16

+1

不僅功能。屬性的初始值也應該在原型上聲明 - 如果所有的對象實例都有一個屬性「obj.type == 4」,除非明確地改變,那麼在原型上聲明'type:4'是最合理的,而不是分配這個每次在構造函數中的值。但是,正如我所說的,您應該小心地在原型中分配非原始類型(對象或數組),因爲這些可以更改,並且您可能不希望這些更改影響所有對象實例。 – 2011-06-08 09:45:55

5

第一種方法(我們稱之爲類型1)將area()函數添加到對象本身。每次用new構造一個circle對象時,其主體將被複製到(!)到新實例。

第二種方法(類型2)將area()函數添加到對象原型(原型是層次結構中的「上一層」)。每次創建circle的新實例時,只會複製radius屬性。

現在,當您在第二個對象的實例上調用area()時,JavaScript無法在該對象本身上找到該函數。現在它「上升」了原型鏈,並使用它找到的那個名稱的第一個函數。

現在,這有幾方面的含義:

  1. 新的對象實例將會更小(更少的物理代碼)
  2. 您可以一次同時改變area實施2型的所有現有對象他們住(通過改變原型),你不能這樣做類型1
  3. 你可以覆蓋功能area類型2的單個實例,同時保持功能的「原始實現」
+0

cw'd它,因爲這個問題將被關閉重複。 – Tomalak 2011-06-08 08:51:01

+0

謝謝@Tomalak – 2011-06-08 08:54:32