Funzione Prototipo Proprietà

Il prototipo la proprietà è un oggetto creato da JavaScript per ogni Funzione() esempio. In particolare, collega le istanze dell'oggetto create con nuovo parola chiave torna alla funzione di costruzione che li ha creati. Questo è fatto in modo che le istanze possano condividere, o ereditare, metodi e proprietà comuni. È importante sottolineare che la condivisione si verifica durante la ricerca della proprietà. Ricorda dal primo articolo che ogni volta che cerchi o accedi a una proprietà su un oggetto, la proprietà verrà ricercata sull'oggetto e sulla catena del prototipo.

Un oggetto prototipo viene creato per ogni funzione, indipendentemente dal fatto che si intenda utilizzare tale funzione come costruttore.

Nel codice seguente, costruisco un array dal Array () costruttore, e poi invoco il aderire() metodo.

Esempio: sample118.html

 

Il aderire() il metodo non è definito come una proprietà di myArray istanza di oggetto, ma in qualche modo abbiamo accesso a aderire() come se lo fosse. Questo metodo è definito da qualche parte, ma dove? Bene, è definito come una proprietà del Array () proprietà prototipo del costruttore. Da aderire() non si trova all'interno dell'istanza dell'oggetto dell'array, JavaScript cerca la catena del prototipo per un metodo chiamato aderire().

Ok, allora perché le cose sono fatte in questo modo? In realtà, si tratta di efficienza e riutilizzo. Perché ogni istanza dell'array creata dalla funzione di costruzione dell'array deve essere definita in modo univoco aderire() metodo quando aderire() funziona sempre allo stesso modo? Ha più senso per tutti gli array sfruttare lo stesso aderire() funzione senza dover creare una nuova istanza della funzione per ogni istanza di array.

Questa efficienza di cui parliamo è possibile a causa del prototipo proprietà, il collegamento del prototipo e la catena di ricerca del prototipo. In questo articolo, suddividiamo questi attributi spesso confusi dell'ereditarietà prototipale. Ma a dire il vero, starai meglio memorizzando semplicemente i meccanismi di come funziona effettivamente la gerarchia delle catene. Fare riferimento al primo articolo se è necessario un aggiornamento su come vengono risolti i valori delle proprietà.


Perché preoccuparsi di prototipo Proprietà?

Dovresti preoccuparti per il prototipo proprietà per quattro motivi.

Motivo 1

La prima ragione è che la proprietà prototype viene utilizzata dalle funzioni di costruzione native (Oggetto(), Array (), Funzione(), ecc.) per consentire alle istanze del costruttore di ereditare proprietà e metodi. È il meccanismo utilizzato da JavaScript stesso per consentire alle istanze dell'oggetto di ereditare proprietà e metodi dalle funzioni del costruttore prototipo proprietà. Se vuoi capire meglio JavaScript, devi capire in che modo lo stesso JavaScript sfrutta il prototipo oggetto.

Motivo 2

Quando si creano funzioni di costruzione definite dall'utente, è possibile orchestrare l'ereditarietà allo stesso modo degli oggetti nativi JavaScript. Ma prima devi imparare come funziona.

Motivo 3

Potresti non gradire l'ereditarietà del prototipo o preferire un altro modello per l'ereditarietà degli oggetti, ma in realtà un giorno potresti dover modificare o gestire il codice di qualcun altro che pensava che l'eredità prototipale fosse le ginocchia delle api. Quando ciò accade, devi essere a conoscenza di come funziona l'ereditarietà prototipale, nonché del modo in cui può essere replicata dagli sviluppatori che fanno uso di funzioni di costruzione personalizzate.

Motivo 4

Utilizzando l'ereditarietà prototipale, è possibile creare istanze di oggetti efficienti che sfruttano tutti gli stessi metodi. Come già accennato, non tutti gli oggetti dell'array, che sono istanze del Array () costruttore, hanno bisogno di loro aderire() metodi. Tutte le istanze possono sfruttare lo stesso aderire() metodo perché il metodo è memorizzato nella catena del prototipo.

Il prototipo è standard su tutti Funzione() istanze

Tutte le funzioni sono create da a Funzione() costruttore, anche se non invochi direttamente il Funzione() costruttore (var add = new Function ('x', 'y', 'return x + z');) e utilizzare invece la notazione letterale (var add = function (x, y) return x + z;).

Quando viene creata un'istanza di funzione, viene sempre data a prototipo proprietà, che è un oggetto vuoto. Nel seguente esempio, definiamo una funzione chiamata myFunction e quindi accediamo a prototipo proprietà che è semplicemente un oggetto vuoto.

Esempio: sample119.html

 

Assicurati di comprendere completamente che la proprietà del prototipo proviene dal Funzione() costruttore. Solo una volta che intendiamo utilizzare la nostra funzione come funzione di costruzione definita dall'utente, la proprietà del prototipo viene sfruttata, ma ciò non cambia il fatto che Funzione() costruttore fornisce ad ogni istanza una proprietà prototipo.


Il predefinito prototipo La proprietà è un Oggetto() Oggetto

Tutto questo prototipo parlare può diventare un po 'pesante. Veramente, prototipo è solo una proprietà di oggetto vuota chiamata "prototipo" creata dietro le quinte da JavaScript e resa disponibile invocando il Funzione() costruttore. Se dovessi farlo manualmente, sarebbe simile a questo:

Esempio: sample120.html

 

In effetti, questo codice di esempio funziona davvero bene, essenzialmente solo la duplicazione di ciò che JavaScript già fa.

Il valore di una proprietà prototype può essere impostato su uno qualsiasi dei valori complessi (oggetti) disponibili in JavaScript. JavaScript ignorerà qualsiasi proprietà prototipo impostata su un valore primitivo.


Le istanze create da una funzione di costruzione sono collegate a quelle del costruttore prototipo Proprietà

Mentre è solo un oggetto, prototipo è speciale perché la catena prototipo collega ogni istanza alla proprietà prototipo della sua funzione di costruzione. Ciò significa che ogni volta che un oggetto viene creato da una funzione di costruzione usando il nuovo keyword (o quando viene creato un object wrapper per un valore primitivo), aggiunge un collegamento nascosto tra l'istanza dell'oggetto creata e la proprietà prototype della funzione di costruzione utilizzata per crearlo. Questo collegamento è noto all'interno dell'istanza come __proto__ (sebbene sia esposto / supportato tramite codice in Firefox 2+, Safari, Chrome e Android). JavaScript lo collega insieme in background quando viene invocata una funzione di costruzione e questo link che consente alla catena di prototipi di essere, beh, una catena. Nel seguente esempio, aggiungiamo una proprietà al nativo Array () costruttori prototipo, che possiamo quindi accedere da un Array () istanza usando il __proto__ proprietà impostata su quell'istanza.

Esempio: sample121.html

 

Dall'accesso __proto__ non fa parte dello standard ufficiale ECMA, c'è un modo più universale per tracciare il collegamento da un oggetto all'oggetto prototipo che eredita, e cioè utilizzando il costruttore proprietà. Questo è dimostrato nel seguente esempio.

Esempio: sample122.html

 

In questo esempio, il foo la proprietà si trova all'interno dell'oggetto prototipo. È necessario rendersi conto che ciò è possibile solo a causa dell'associazione tra l'istanza di Array () e il Array () oggetto prototipo costruttore (Array.prototype). In poche parole, myArray .__ proto__ (o myArray.constructor.prototype) Riferimenti Array.prototype.


Ultima fermata nel prototipo Catena è Object.prototype

Poiché la proprietà prototype è un oggetto, l'ultima fermata nella catena o nella ricerca del prototipo è Object.prototype. Nel codice che segue, creo myArray, che è una matrice vuota. Quindi tento di accedere a una proprietà di myArray che non è stato ancora definito, impegnando la catena di ricerca prototipo. Il myArray l'oggetto viene esaminato per la proprietà foo. Essendo assente, la proprietà è cercata a Array.prototype, ma non è neanche lì. L'aspetto finale di JavaScript è quindi Object.prototype. Perché non è definito in nessuno di questi tre oggetti, la proprietà è non definito.

Esempio: sample123.html

 

Prendi nota che la catena si è fermata con Object.prototype. L'ultimo posto che cercavamo era foo Object.prototype.

Attento! Qualsiasi cosa aggiunta a Object.prototype verrà visualizzata in ciclo for in.


Il prototipo Chain Restituisce la prima proprietà trovata trovata nella catena

Come la catena di portata, il prototipo chain utilizzerà il primo valore che trova durante la ricerca della catena.

Modifica dell'esempio di codice precedente, se abbiamo aggiunto lo stesso valore a Object.prototype e Array.prototype oggetti, e quindi ha tentato di accedere a un valore su un'istanza di array, il valore restituito sarebbe da Array.prototype oggetto.

Esempio: sample124.html

 

In questo esempio, il valore di foo a Array.prototype.foo è ombreggiare, o mascherare, il foo valore trovato a Object.prototype.foo. Ricorda che la ricerca termina quando la proprietà viene trovata nella catena, anche se lo stesso nome di proprietà viene utilizzato anche più in alto nella catena.


Sostituire il prototipo La proprietà con un nuovo oggetto rimuove la proprietà del costruttore di default

È possibile sostituire il valore predefinito di a prototipo proprietà con un nuovo valore. Tuttavia, così facendo eliminerà la proprietà predefinita del costruttore trovata nel "pre-made" prototipo oggetto a meno che non ne specifichi manualmente uno.

Nel codice che segue, creiamo a foo funzione di costruzione, sostituire il prototipo proprietà con un nuovo oggetto vuoto e verificare che la proprietà del costruttore sia interrotta (ora fa riferimento a quella meno utile Oggetto prototipo).

Esempio: sample125.html

 

Se si intende sostituire l'impostazione predefinita prototipo proprietà (in comune con alcuni pattern JS OOP) impostata da JavaScript, è necessario collegare di nuovo una proprietà del costruttore che fa riferimento alla funzione del costruttore. Nel seguente esempio, modifichiamo il nostro codice precedente in modo che il costruttore la proprietà fornirà nuovamente un riferimento alla corretta funzione di costruzione.

Esempio: sample126.html

 

Istanze da cui ereditare le proprietà prototipo Otterrà sempre gli ultimi valori

La proprietà prototype è dinamica nel senso che le istanze otterranno sempre l'ultimo valore dal prototipo indipendentemente da quando è stato istanziato, modificato o aggiunto. Nel codice che segue, creiamo a foo costruttore, aggiungi la proprietà X al prototipo, e quindi creare un'istanza di Foo () di nome FooInstance. Successivamente, registriamo il valore di X. Quindi aggiorniamo il valore di prototipo di x e lo registriamo nuovamente per scoprire che la nostra istanza ha accesso all'ultimo valore trovato nel file prototipo oggetto.

Esempio: sample127.html

 

Dato il funzionamento della catena di ricerca, questo comportamento non dovrebbe essere così sorprendente. Se ti stai chiedendo, questo funziona allo stesso modo indipendentemente dal fatto che tu usi l'impostazione predefinita prototipo oggetto o ignorarlo con il tuo. Nel prossimo esempio, sostituisco il valore predefinito prototipo oggetto di dimostrare questo fatto.

Esempio: sample128.html

 

Sostituire il prototipo La proprietà con un nuovo oggetto non aggiorna le istanze precedenti

Potresti pensare di poter sostituire il prototipo proprietà interamente in qualsiasi momento e che tutte le istanze saranno aggiornate, ma questo non è corretto. Quando crei un'istanza, quell'istanza sarà legata a prototipo quello era stato coniato al momento dell'istanziazione. Fornire un nuovo oggetto come la proprietà del prototipo non aggiorna la connessione tra istanze già create e la nuova prototipo.

Ma ricorda, come ho affermato in precedenza, che puoi aggiornare o aggiungere all'originale creato prototipo oggetto e quei valori rimangono collegati alle prime istanze.

Esempio: sample129.html

 

L'idea chiave da portare via qui è che un prototipo di oggetti non dovrebbe essere sostituito con un nuovo oggetto una volta che inizi a creare istanze. In questo modo, le istanze avranno un collegamento a diversi prototipi.

Costruttori definiti dall'utente possono sfruttare lo stesso prototipo Ereditarietà come costruttori nativi

Si spera che a questo punto dell'articolo si stia affondando nel modo in cui lo stesso JavaScript sfrutta il prototipo proprietà per eredità (Array.prototype). Questo stesso modello può essere sfruttato durante la creazione di funzioni di costruzione non native e definite dall'utente. Nel seguente esempio, prendiamo il classico Persona oggetto e imitare il modello che JavaScript utilizza per l'ereditarietà.

Esempio: sample130.html

 

In questo codice, a Persona() viene creata la funzione di costruzione. Quindi aggiungiamo proprietà al prototipo proprietà di Persona(), che può essere ereditato da tutte le istanze. Chiaramente, puoi sfruttare la catena di prototipi nel tuo codice nello stesso modo in cui JavaScript lo sfrutta per l'ereditarietà di oggetti nativi.

Come buon esempio di come si può sfruttare questo, è possibile creare una funzione di costruzione le cui istanze ereditano il file gambe e braccia proprietà se non vengono fornite come parametri. Nel seguente esempio, se il Persona() costruttore viene inviato parametri, i parametri vengono utilizzati come proprietà di istanza, ma se uno o più parametri non vengono forniti, vi è un fallback. Queste proprietà dell'istanza ombreggiano o mascherano le proprietà ereditate, offrendoti il ​​meglio di entrambi i mondi.

Esempio: sample131.html

 

Creazione di catene di ereditarietà (l'intenzione originale)

L'ereditarietà prototipale è stata concepita per consentire catene ereditarie che imitano i modelli di ereditarietà trovati nei tradizionali linguaggi di programmazione orientati agli oggetti. Affinché un oggetto erediti da un altro oggetto in JavaScript, tutto ciò che devi fare è istanziare un'istanza dell'oggetto da cui vuoi ereditare e assegnarla al prototipo proprietà dell'oggetto che sta eseguendo l'ereditarietà.

Nell'esempio di codice che segue, capocuoco oggetti (cody) ereditato da Persona(). Ciò significa che se una proprietà non viene trovata in a capocuoco oggetto, verrà quindi cercato sul prototipo della funzione che ha creato Persona() oggetti. Per cablare l'eredità, tutto ciò che devi fare è istanziare un'istanza di Persona() come valore per Chef.prototype (Chef.prototype = new Person (); ).

Esempio: sample132.html

 

Conclusione

Tutto ciò che abbiamo fatto in questo esempio è stato sfruttare un sistema che era già in atto con gli oggetti nativi. Considera che Persona() non è diverso dal default Oggetto() valore per le proprietà del prototipo. In altre parole, questo è esattamente ciò che accade quando una proprietà prototipo, contenente il suo predefinito vuoto Oggetto() valore, guarda al prototipo della funzione di costruzione creata (Object.prototype) per proprietà ereditate.