6

我經常看到這種模式來定義JavaScript對象原型爲什麼定義特性被認爲是一個反

function Person(name) { 
    this.name = name; 
} 
Person.prototype.describe = function() { 
    return "Person called "+this.name; 
}; 

而且在this article它說,直接添加屬性原型objct被認爲是一個反模式。

來自「古典基於類」的語言,必須定義方法以外的屬性聽起來不太正確,更在JavaScript中,其中一個方法應該只是一個具有函數值的屬性(我在這裏嗎? )

我想知道如果任何人都可以解釋這一點,甚至提出一個更好的方式來處理這些情況

+5

它說「數據屬性」,我相信它是指變量。我不認爲它提到了向原型添加功能的任何事情。 – 2012-08-10 14:54:54

+0

arxanas說什麼。確切的引用是:「一個類的主體只能包含方法,沒有數據屬性,具有數據屬性的原型通常被認爲是反模式,所以這只是一個最佳實踐。」換句話說,通過「數據屬性」,作者的意思是「不屬於方法/功能的屬性」。 – ruakh 2012-08-10 14:57:44

+0

你的問題是基於一個誤解,不知道該怎麼做。我永遠不會記得看到數據被放置在原型上。我不能真正編輯你的問題在原型中有數據,因爲這不是我經常看到的*模式。 – Esailija 2012-08-10 14:58:22

回答

6

在通常的面向對象的語言中,您定義了描述成員,方法和構造函數的類。

在JS中,「類」的定義(它不像其他語言中的類一樣...有時使用術語僞類)是構造函數本身。如果你的對象是由name parametrised,是有意義的編寫

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

即財產name必須在構造函數中設置。

當然,你可以寫

function Person(name) { 
    this.name = name; 
    this.describe = function() { ... }; 
} 

和你希望它會工作。

但是,在這種情況下,您正在爲構造函數的每次調用創建一個單獨的方法實例。

在另一方面,在這裏:

Person.prototype.describe = function() { 
    return "Person called "+this.name; 
}; 

你只有一次定義方法。 Person的所有實例都會收到一個指針(__proto__,大多數瀏覽器中的程序員都無法訪問)到Person.prototype。所以,如果你

var myPerson = new Person(); 
myPerson.describe(); 

它會工作,因爲JS直接觀察對象成員中的對象,然後在它的原型等,一路到Object.prototype

問題是,在第二種情況下,只有一個函數實例存在。你可能會同意這是一個更好的設計。即使你不這樣做,它只需要更少的內存。

+1

非常感謝,我沒有意識到,從構造函數的每個方法定義將是一個不同的函數實例... – opensas 2012-08-10 15:17:46

3

由於arxanas說,文中提到數據性能

我假設的原因是數據通常是特定於實例,所以將其添加到原型沒有任何意義。

此外,如果您的數據是可變類型,例如一個數組,然後將其分配給原型,然後該數組實例在所有實例之間共享,並且不能像每個實例都有自己的數組一樣使用它。


例子:下導致不正確的行爲:

function Set() { 

} 

// shared between instances 
// each instance adds values to **the same** array 
Set.prototype.elements = []; 

Set.prototype.add = function(x) { 
    this.elements.push(x); 
}; 

它應該是:

function Set() { 
    // each instance gets its own array 
    this.elements = []; 
} 

Set.prototype.add = function(x) { 
    this.elements.push(x); 
}; 

概括起來:

  • 將應該在所有實例之間共享的屬性添加到原型。
  • 在構造函數中分配實例特定的數據。
1

就像arxanas在他的評論中寫道。原型中的數據屬性與傳統的oop中的類級變量差不多。除非您有非常特殊的需求,否則這些服務不會每天使用。就這樣。

5

該代碼沒有問題。推測這是什麼意思:

function Person(name) { 
    this.name = name; 
} 
Person.prototype.age = 15; //<= adding a hardcoded property to the prototype 

現在你會看到:

var pete = new Person('Pete'), mary = new Person('Mary'); 
pete.age; //=> 15 
mary.age //=> 15 

而且大部分時間,這不是你想要的。分配給構造函數原型的屬性在所有實例之間共享,在構造函數中分配的屬性(this.name)是特定於實例的屬性。

1

在原型上聲明屬性根本不是反模式。當我看到一個對象時,我認爲「這就是這種類型的原型對象對數據和方法的作用。」

其他人已經警告不要在原型中給屬性一個參考值,例如:Foo.prototype.bar = []; ---因爲數組和對象是引用類型。引用類型是不可變的,因此「類」的每個實例都指向相同的數組或對象。只需在原型中將它們設置爲null,然後在構造函數中給它們一個值。

我總是在原型中包含所有屬性,其中一個非常明確的原因是:向其他程序員傳達哪些屬性可公開提供,以及它們的默認值是什麼,而不需要通過構造函數篩選出來。

如果您要創建需要文檔的共享庫,這將變得特別有用。

考慮這個例子:

/** 
* class Point 
* 
* A simple X-Y coordinate class 
* 
* new Point(x, y) 
* - x (Number): X coordinate 
* - y (Number): Y coordinate 
* 
* Creates a new Point object 
**/ 
function Point(x, y) { 
    /** 
    * Point#x -> Number 
    * 
    * The X or horizontal coordinate 
    **/ 
    this.x = x; 

    /** 
    * Point#y -> Number 
    * 
    * The Y or vertical coordinate 
    **/ 
    this.y = y; 
} 

Point.prototype = { 
    constructor: Point, 

    /** 
    * Point#isAbove(other) -> bool 
    * - other (Point): The point to compare this to 
    * 
    * Checks to see if this point is above another 
    **/ 
    isAbove: function(other) { 
     return this.y > other.y; 
    } 
}; 

(文檔格式:PDoc

只是閱讀文檔這裏是一個有點尷尬,因爲有關xy性質的信息嵌入在構造函數中。對比,與包括原型這些特性的「反模式」:

/** 
* class Point 
* 
* A simple X-Y coordinate class 
* 
* new Point(x, y) 
* - x (Number): X coordinate 
* - y (Number): Y coordinate 
* 
* Creates a new Point object 
**/ 
function Point(x, y) { 
    this.x = x; 
    this.y = y; 
} 

Point.prototype = { 

    /** 
    * Point#x -> Number 
    * 
    * The X or horizontal coordinate 
    **/ 
    x: 0, 

    /** 
    * Point#y -> Number 
    * 
    * The Y or vertical coordinate 
    **/ 
    y: 0, 

    constructor: Point, 

    /** 
    * Point#isAbove(other) -> bool 
    * - other (Point): The point to compare this to 
    * 
    * Checks to see if this point is above another 
    **/ 
    isAbove: function(other) { 
     return this.y > other.y; 
    } 

}; 

現在看看樣機給你的實際對象的快照,這是很容易在你的頭上來可視化,也更容易供作者撰寫文檔。構造函數也不會與文檔混雜在一起,並且堅持將對象帶入生活的業務。

該原型具有一切,並且是關於「原型」Point對象對於方法數據具有什麼樣的信息的標準來源。

我會爭辯說不是包括原型中的數據屬性是反模式。

相關問題