6

vedo spesso questo schema per definire oggetti JavaScriptproprietà Perché definiscono nel prototipo è considerato un antipattern

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

E in this article si dice che l'aggiunta di proprietà direttamente al prototipo objct è considerato un antipattern.

Provenendo da linguaggi "class class based", dovendo definire le proprietà oltre ai metodi non sembra giusto, sempre in javascript, dove un metodo dovrebbe essere solo una proprietà con un valore di funzione (sono qui?)

volevo sapere se qualcuno può spiegare questo, o anche suggerire un modo migliore per gestire queste situazioni

+5

Dice "proprietà dei dati", che a mio avviso si riferisce alle variabili. Non penso che menzioni nulla sull'aggiunta di funzioni a un prototipo. –

+0

Che cosa hanno detto arxanas. L'esatto preventivo è, "Un corpo di classe può contenere solo metodi, nessuna proprietà di dati. I prototipi con proprietà di dati sono generalmente considerati un anti-pattern, quindi questo semplicemente impone una best practice." In altre parole, per "proprietà dei dati" l'autore significa "proprietà che non sono metodi/funzioni". – ruakh

+0

La tua domanda si basa su un malinteso, non so cosa fare. Non ricordo nemmeno di aver visto i dati inseriti nel prototipo. Non posso davvero modificare la tua domanda per avere dati nel prototipo perché non è un pattern * Spesso vedo *. – Esailija

risposta

6

Nei soliti linguaggi orientati agli oggetti, si ha una definizione della classe che descrive membri, metodi e costruttore.

In JS, la definizione della "classe" (non è proprio la classe come in altri linguaggi ... a volte viene usato il termine pseudoclass) è il costruttore stesso. Se l'oggetto è parametrizzato da name, ha senso scrivere

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

vale a dire la proprietà name deve essere impostato nel costruttore.

Naturalmente, è possibile scrivere

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

e funzionerà come previsto.

Tuttavia, in questo caso si sta creando un'istanza separata del metodo con ogni chiamata del costruttore.

D'altra parte, qui:

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

si definisce solo il metodo di una volta. Tutte le istanze di Person riceveranno un puntatore (chiamato __proto__ e non accessibile dal programmatore nella maggior parte dei browser) a Person.prototype. Quindi, se si chiama

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

che funzionerà, perché JS sembra membri oggetto direttamente l'oggetto, poi nel suo prototipo, ecc tutta la strada fino a Object.prototype.

Il punto è che nel secondo caso esisterà solo un'istanza della funzione. Che probabilmente concorderai che è un design migliore. E anche se non lo fai, richiede semplicemente meno memoria.

+1

grazie mille, non mi ero reso conto che ogni definizione di metodo dal costruttore sarebbe stata diversa dalla funzione ... – opensas

3

come dice arxanas, l'articolo cita proprietà dei dati.

Il motivo, presumo, è che i dati sono in genere specifici di un'istanza, quindi non ha senso aggiungerlo al prototipo.

Inoltre, se i dati sono di tipo mutabile, ad es. un array e lo si assegna al prototipo, quindi questa istanza dell'array viene condivisa tra tutte le istanze e non è possibile utilizzarla come se ogni istanza avesse il proprio array.


Esempio: I seguenti porta a comportamenti scorretti:

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); 
}; 

dovrebbe essere:

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

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

Per riassumere:

  • Aggiungere proprietà che devono essere condivise tra tutte le istanze sul prototipo.
  • Assegnare dati specifici dell'istanza all'interno della funzione di costruzione.
1

Proprio come arxanas ha scritto nel suo commento. Le proprietà dei dati nel prototipo sono più o meno simili alle variabili di livello di classe nell'opta tradizionale. E questi non vengono utilizzati su base giornaliera, a meno che non si abbia un bisogno molto specifico. È tutto.

5

Non c'è niente di sbagliato in questo codice. Questo è presumibilmente ciò che si intende:

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

Ora si vedrà questo:

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

E la maggior parte del tempo, che non è ciò che si desidera. Le proprietà assegnate al prototipo di un costruttore sono condivise tra tutte le istanze, le proprietà assegnate all'interno del costruttore (this.name) sono specifiche per l'istanza.

1

Dichiarare le proprietà su un prototipo non è affatto un modello anti. Quando guardo un oggetto prototype, penso "questo è ciò che l'oggetto prototipo di questo tipo ha per dati e metodi".

Altri hanno messo in guardia dal fornire alle proprietà un valore di riferimento nel prototipo, ad esempio: Foo.prototype.bar = []; --- perché le matrici e gli oggetti sono tipi di riferimento. Un tipo di riferimento è immutabile, quindi ogni istanza di una "classe" si riferisce alla stessa matrice o oggetto. Basta impostarli su null nel prototipo, quindi assegnare loro un valore nel costruttore.

Includo sempre tutte le proprietà nel prototipo per una ragione molto chiara: Comunicando ad altri programmatori quali proprietà sono disponibili pubblicamente e quali sono i loro valori predefiniti senza richiedere loro di setacciare un costruttore per capirlo.

Ciò risulta particolarmente utile se si sta creando una libreria condivisa che richiede la documentazione.

consideri questo esempio: (formato Documentazione: PDoc)

/** 
* 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; 
    } 
}; 

Basta leggere la documentazione è un po 'scomodo qui perché le informazioni sulle proprietà x e y sono integrati all'interno della funzione di costruzione.Contrasto che con il "anti-modello" di includere queste proprietà nel prototipo:

/** 
* 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; 
    } 

}; 

Ora guardando il prototipo fornisce un'istantanea dell'oggetto reale, che è molto più facile da visualizzare nella tua testa, e più facile per l'autore di scrivere la documentazione. Anche la funzione di costruzione non è ingombra di documentazione e si attiene al business di dare vita a un oggetto Point.

Il prototipo ha tutto, ed è la fonte canonica di informazioni su ciò che il "prototipo" Point oggetto ha per entrambi i metodi ei dati .

Direi che lo non incluse le proprietà dei dati nel prototipo è il modello anti.