mdn - use prototype javascript




Come funziona JavaScript.prototype? (16)

Non lo sono in linguaggi di programmazione dinamici, ma ho scritto la mia giusta dose di codice JavaScript. Non ho mai avuto la testa su questa programmazione basata su prototipi, qualcuno sa come funziona?

var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Ricordo una lunga discussione che ho avuto con le persone un po 'indietro (non sono esattamente sicuro di quello che sto facendo) ma, a quanto ho capito, non esiste un concetto di classe. È solo un oggetto, e le istanze di quegli oggetti sono cloni dell'originale, giusto?

Ma qual è lo scopo esatto di questa proprietà ".prototype" in JavaScript? Come si relaziona all'istanziazione di oggetti?

Aggiornamento: modo corretto

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

Anche queste slides davvero aiutato molto.


qual è lo scopo esatto di questa proprietà ".prototype"?

L'interfaccia con le classi standard diventa estensibile. Ad esempio, stai utilizzando la Arrayclasse e devi anche aggiungere un serializzatore personalizzato per tutti gli oggetti dell'array. Trascorreresti del tempo a codificare una sottoclasse, o usare la composizione o ... La proprietà prototype risolve questo consentendo agli utenti di controllare l'insieme esatto di membri / metodi disponibili per una classe.

Pensa ai prototipi come un puntatore a vtable in più. Quando alcuni membri mancano dalla classe originale, il prototipo viene esaminato in fase di runtime.


I sette Koan del prototipo

Mentre Ciro San scendeva sul monte Fire Fox dopo una profonda meditazione, la sua mente era chiara e pacifica.

La sua mano tuttavia era inquieta e da sola afferrò un pennello e annotò le seguenti note.

0) Due cose diverse possono essere chiamate "prototipo":

  • la proprietà prototype, come in obj.prototype

  • la proprietà interna del prototipo, indicata come [[Prototype]] in ES5 .

    Può essere recuperato tramite ES5 Object.getPrototypeOf() .

    Firefox lo rende accessibile tramite la proprietà __proto__ come estensione. ES6 ora menziona alcuni requisiti opzionali per __proto__ .

1) Questi concetti esistono per rispondere alla domanda:

Quando obj.property , dove cerca JS .property ?

Intuitivamente, l'ereditarietà classica dovrebbe influenzare la ricerca delle proprietà.

2)

  • __proto__ è usato per il punto . ricerca della proprietà come nella proprietà obj.property .
  • .prototype non è utilizzato per la ricerca direttamente, solo indirettamente in quanto determina __proto__ alla creazione dell'oggetto con new .

L'ordine di ricerca è:

  • proprietà oggetto aggiunte con obj.p = ... o Object.defineProperty(obj, ...)
  • proprietà di obj.__proto__
  • proprietà di obj.__proto__.__proto__ , e così via
  • se qualche __proto__ è null , restituisce undefined .

Questa è la cosiddetta catena di prototipi .

Puoi evitare ricerca con obj.hasOwnProperty('key') e Object.getOwnPropertyNames(f)

3) Ci sono due modi principali per impostare obj.__proto__ :

  • new :

    var F = function() {}
    var f = new F()
    

    allora il new ha impostato:

    f.__proto__ === F.prototype
    

    È qui .prototype viene utilizzato .prototype .

  • Object.create :

     f = Object.create(proto)
    

    imposta:

    f.__proto__ === proto
    

4) Il codice:

var F = function() {}
var f = new F()

Corrisponde allo schema seguente:

(Function)       (  F  )                                      (f)
 |  ^             | | ^                                        |
 |  |             | | |                                        |
 |  |             | | +-------------------------+              |
 |  |constructor  | |                           |              |
 |  |             | +--------------+            |              |
 |  |             |                |            |              |
 |  |             |                |            |              |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |
 |  |             |                |            |              |
 |  |             |                | +----------+              |
 |  |             |                | |                         |
 |  |             |                | | +-----------------------+
 |  |             |                | | |
 v  |             v                v | v
(Function.prototype)              (F.prototype)
 |                                 |
 |                                 |
 |[[Prototype]]                    |[[Prototype]]
 |                                 |
 |                                 |
 | +-------------------------------+
 | |
 v v
(Object.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

Questo diagramma mostra molti nodi di oggetti predefiniti nella lingua: null , Object , Object.prototype , Function e Function.prototype . Le nostre 2 linee di codice hanno creato solo f , F e F.prototype .

5). Il .constructor normalmente proviene da F.prototype attraverso il . consultare:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

Quando scriviamo f.constructor , JavaScript fa il . ricerca come:

  • f non ha il .constructor
  • f.__proto__ === F.prototype ha .constructor === F , quindi prendilo

Il risultato f.constructor == F è intuitivamente corretto, poiché F è usato per costruire f , ad es. Set fields, molto simile ai classici linguaggi OOP.

6) La sintassi dell'ereditarietà classica può essere ottenuta manipolando catene di prototipi.

ES6 aggiunge la class ed extends parole chiave, che sono semplicemente lo zucchero di sintassi per la follia di manipolazione del prototipo precedentemente possibile.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
(new C(1)).inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

Diagramma semplificato senza tutti gli oggetti predefiniti:

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

Dopo aver letto questo thread, mi sento confuso con JavaScript Prototype Chain, quindi ho trovato questi grafici

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance

è un grafico chiaro per mostrare JavaScript Inheritance di Prototype Chain

e

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

questo contiene un esempio con codice e diversi diagrammi.

la catena del prototipo ricade infine su Object.prototype.

la catena di prototipi può essere tecnicamente estesa per tutto il tempo che vuoi, ogni volta impostando il prototipo della sottoclasse uguale a un oggetto della classe genitore.

Spero che sia anche utile per te capire la catena del prototipo JavaScript.


In una lingua che implementa l'ereditarietà classica come Java, C # o C ++ si inizia creando una classe - un modello per i propri oggetti - e quindi è possibile creare nuovi oggetti da quella classe o estendere la classe, definendo una nuova classe che aumenta la lezione originale

In JavaScript si crea per la prima volta un oggetto (non esiste un concetto di classe), quindi è possibile aumentare il proprio oggetto o creare nuovi oggetti da esso. Non è difficile, ma un po 'estraneo e difficile da metabolizzare per qualcuno abituato al modo classico.

Esempio:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

Fino ad ora ho esteso l'oggetto base, ora creo un altro oggetto e poi eredito da Person.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

var Person = function (name) {
    this.name = name;
};
Person.prototype.getName = function () {
    return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
    this.name = name;
};
Customer.prototype = new Person();

var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
    return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Mentre come detto non posso chiamare setAmountDue (), getAmountDue () su una persona.

//The following statement generates an error.
john.setAmountDue(1000);

Ogni oggetto JavaScript ha una proprietà interna chiamata [[Prototipo]] . Se cerchi una proprietà tramite obj.propName o obj['propName'] e l'oggetto non ha tale proprietà - che può essere controllata tramite obj.hasOwnProperty('propName') - il runtime ricerca la proprietà nell'oggetto referenziato da [[Prototipo]]. Se anche l'oggetto prototipo non ha tale proprietà, il suo prototipo viene verificato a sua volta, percorrendo così la catena prototipo dell'oggetto originale fino a quando non viene trovata una corrispondenza o viene raggiunta la sua fine.

Alcune implementazioni di JavaScript consentono l'accesso diretto alla proprietà [[Prototipo]], ad esempio tramite una proprietà non standard denominata __proto__ . In generale, è possibile impostare il prototipo di un oggetto solo durante la creazione dell'oggetto: se si crea un nuovo oggetto tramite la new Func() , la proprietà [[Prototype]] dell'oggetto verrà impostata sull'oggetto a cui fa riferimento Func.prototype .

Ciò consente di simulare classi in JavaScript, sebbene il sistema di ereditarietà di JavaScript sia - come abbiamo visto - prototipico e non basato su classi:

Basti pensare alle funzioni del costruttore come classi e alle proprietà del prototipo (cioè dell'oggetto referenziato dalla proprietà prototype della funzione di costruzione) come membri condivisi, ovvero membri che sono gli stessi per ogni istanza. Nei sistemi basati su classi, i metodi vengono implementati allo stesso modo per ogni istanza, quindi i metodi vengono normalmente aggiunti al prototipo, mentre i campi di un oggetto sono specifici dell'istanza e quindi aggiunti all'oggetto stesso durante la costruzione.


Ogni oggetto ha una proprietà interna, [[Prototipo]], che lo collega a un altro oggetto:

object [[Prototype]] -> anotherObject

Nel javascript tradizionale, l'oggetto collegato è la proprietà prototype di una funzione:

object [[Prototype]] -> aFunction.prototype

Alcuni ambienti espongono [[Prototipo]] come __proto__ :

anObject.__proto__ === anotherObject

Si crea il collegamento [[Prototipo]] durante la creazione di un oggetto.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

Quindi queste affermazioni sono equivalenti:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

Una new istruzione non mostra il target di collegamento ( Object.prototype ) stesso; invece il target è implicito dal costruttore ( Object ).

Ricorda:

  • Ogni oggetto ha un collegamento, [[Prototipo]], a volte esposto come __proto__ .
  • Ogni funzione ha una proprietà prototype .
  • Gli oggetti creati con new sono collegati alla proprietà prototype del loro costruttore.
  • Se una funzione non viene mai utilizzata come costruttore, la sua proprietà prototype verrà utilizzata.
  • Se non hai bisogno di un costruttore, usa Object.create invece di new .

È solo che hai già un oggetto con Object.new ma non hai ancora un oggetto quando usi la sintassi del costruttore.



Svolgo un ruolo di insegnante di JavaScript e il concetto di prototipo è sempre stato un argomento controverso da trattare quando insegno. Mi ci è voluto un po 'per trovare un buon metodo per chiarire il concetto, e ora in questo testo cercherò di spiegare come funziona JavaScript .prototype.

Questo è un modello di oggetto basato su prototipo molto semplice che verrebbe considerato come un esempio durante la spiegazione, senza alcun commento ancora:

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

Ci sono alcuni punti cruciali che dobbiamo considerare prima di passare attraverso il prototipo.

1- In che modo funzionano le funzioni JavaScript:

Per fare il primo passo dobbiamo capire come funzionano realmente le funzioni JavaScript, come una funzione di classe che usa this parola chiave al suo interno o semplicemente come una funzione regolare con i suoi argomenti, cosa fa e cosa restituisce.

Diciamo che vogliamo creare un modello di oggetto Person . ma in questo passo cercherò di fare la stessa identica cosa senza usare il prototype e la new parola chiave .

Quindi in questo passaggio functions , objects e this parola chiave, sono tutto ciò che abbiamo.

La prima domanda sarebbe come this parola chiave potrebbe essere utile senza usare new parole chiave .

Quindi per rispondere diciamo che abbiamo un oggetto vuoto e due funzioni come:

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

function getName(){
    console.log(this.name);
}

e ora senza usare new parole chiave come potremmo usare queste funzioni. Quindi JavaScript ha 3 diversi modi per farlo:

un. il primo modo è semplicemente chiamare la funzione come una funzione regolare:

Person("George");
getName();//would print the "George" in the console

in questo caso, questo sarebbe l'attuale oggetto di contesto, che di solito è l'oggetto window globale nel browser o GLOBAL in Node.js Significa che avremmo, window.name nel browser o GLOBAL.name in Node.js, con "George" come valore.

b. Possiamo collegarli a un oggetto, come le sue proprietà

- Il modo più semplice per farlo è modificare l'oggetto person vuota, come:

person.Person = Person;
person.getName = getName;

in questo modo possiamo chiamarli come:

person.Person("George");
person.getName();// -->"George"

e ora l'oggetto person è come:

Object {Person: function, getName: function, name: "George"}

- L'altro modo per collegare una proprietà a un oggetto è utilizzare il prototype di quell'oggetto che può essere trovato in qualsiasi oggetto JavaScript con il nome di __proto__ , e ho cercato di spiegarlo un po 'sulla parte di riepilogo. Quindi potremmo ottenere il risultato simile facendo:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

Ma in questo modo ciò che stiamo facendo è modificare l' Object.prototype , perché ogni volta che creiamo un oggetto JavaScript usando i letterali ( { ... } ), esso viene creato in base a Object.prototype , il che significa che viene collegato al nuovo creato oggetto come un attributo chiamato __proto__ , quindi se lo cambiamo, come abbiamo fatto con il nostro frammento di codice precedente, tutti gli oggetti JavaScript sarebbero stati modificati, non una buona pratica. Quindi quale potrebbe essere la pratica migliore ora:

person.__proto__ = {
    Person: Person,
    getName: getName
};

e ora altri oggetti sono in pace, ma non sembra ancora una buona pratica. Quindi abbiamo ancora una soluzione in più, ma per usare questa soluzione dovremmo tornare a quella linea di codice in cui l'oggetto person stato creato ( var person = {}; ) quindi cambiarlo come:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

ciò che fa è la creazione di un nuovo Object JavaScript e il collegamento __proto__ all'attributo __proto__ . Quindi per essere sicuri di poter fare:

console.log(person.__proto__===propertiesObject); //true

Ma il punto delicato qui è che hai accesso a tutte le proprietà definite in __proto__ al primo livello dell'oggetto person (leggi la parte di riepilogo per maggiori dettagli).

come puoi vedere usando uno di questi due modi, this punterebbe esattamente all'oggetto della person .

c. JavaScript ha un altro modo per fornire la funzione con this , che usa la call o apply per richiamare la funzione.

Il metodo apply () chiama una funzione con un dato valore e argomenti forniti come una matrice (o un oggetto di tipo array).

e

Il metodo call () chiama una funzione con un dato valore e argomenti forniti singolarmente.

in questo modo, che è il mio preferito, possiamo facilmente chiamare le nostre funzioni come:

Person.call(person, "George");

o

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

questi 3 metodi sono i passaggi iniziali importanti per capire la funzionalità .prototype.

2- Come funziona la new parola chiave?

questo è il secondo passo per comprendere la funzionalità .prototype è quello che uso per simulare il processo:

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

in questa parte cercherò di eseguire tutti i passaggi che JavaScript prende, senza utilizzare la new parola chiave e il prototype , quando si utilizza una new parola chiave. così quando facciamo una new Person("George") , la funzione Person funge da costruttore, Questi sono ciò che JavaScript fa, uno per uno:

un. prima di tutto rende un oggetto vuoto, in pratica un hash vuoto come:

var newObject = {};

b. il passo successivo che JavaScript prende è quello di collegare tutti gli oggetti prototipo all'oggetto appena creato

abbiamo my_person_prototype qui simile all'oggetto prototipo.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

Non è il modo in cui JavaScript in realtà allega le proprietà definite nel prototipo. Il modo reale è legato al concetto di catena prototipo.

un. & b. Invece di questi due passaggi puoi ottenere lo stesso risultato facendo:

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

ora possiamo chiamare la funzione my_person_prototype nel nostro my_person_prototype :

newObject.getName();

c. poi dà quell'oggetto al costruttore,

possiamo farlo con il nostro esempio come:

Person.call(newObject, "George");

o

Person.apply(newObject, ["George"]);

quindi il costruttore può fare tutto ciò che vuole, perché questo all'interno di quel costruttore è l'oggetto che è stato appena creato.

ora il risultato finale prima di simulare gli altri passi: Object {name: "George"}

Sommario:

Fondamentalmente, quando si utilizza la nuova parola chiave su una funzione, si sta chiamando su quella funzione e tale funzione funge da costruttore, quindi quando si dice:

new FunctionName()

JavaScript internamente crea un oggetto, un hash vuoto e poi lo dà al costruttore, quindi il costruttore può fare tutto ciò che vuole, perché questo all'interno di quel costruttore è l'oggetto che è stato appena creato e poi ti dà quell'oggetto ovviamente se non hai usato la dichiarazione di ritorno nella tua funzione o se hai inserito un risultato return undefined; alla fine del tuo corpo di funzione.

Quindi, quando JavaScript va a cercare una proprietà su un oggetto, la prima cosa che fa è cercare su quell'oggetto. E poi c'è una proprietà segreta [[prototype]] che di solito è come __proto__ e quella proprietà è ciò che appare in JavaScript al prossimo. E quando guarda attraverso il __proto__ , per quanto è di nuovo un altro oggetto JavaScript, ha il suo attributo __proto__ , va su e su finché non arriva al punto in cui il prossimo __proto__ è nullo. Il punto è l'unico oggetto in JavaScript che il suo attributo __proto__ è null è Object.prototype oggetto Object.prototype :

console.log(Object.prototype.__proto__===null);//true

ed è così che l'ereditarietà funziona in JavaScript.

In altre parole, quando hai una proprietà prototipo su una funzione e ne chiami una nuova, dopo che JavaScript ha terminato di guardare l'oggetto appena creato per le proprietà, andrà a esaminare il .prototype della funzione e inoltre è possibile che questo oggetto ha il suo prototipo interno. e così via.


Ci sono due entità distinte ma correlate qui che hanno bisogno di spiegare:

  • La .prototypeproprietà delle funzioni.
  • La proprietà [[Prototype]] [1] di tutti gli oggetti [2] .

Queste sono due cose diverse.

La [[Prototype]]proprietà:

Questa è una proprietà che esiste su tutti gli [2] oggetti.

Ciò che è memorizzato qui è un altro oggetto, che, come un oggetto stesso, ha un [[Prototype]]suo proprio che punta a un altro oggetto. Questo altro oggetto ha un [[Prototype]]suo proprio. Questa storia continua fino a raggiungere l'oggetto prototipo che fornisce metodi accessibili su tutti gli oggetti (come .toString).

La [[Prototype]]proprietà fa parte di ciò che forma la [[Prototype]]catena. Questa catena di [[Prototype]]oggetti è ciò che viene esaminato quando, ad esempio, [[Get]]o le [[Set]]operazioni vengono eseguite su un oggetto:

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

La .prototypeproprietà:

Questa è una proprietà che si trova solo sulle funzioni. Usando una funzione molto semplice:

function Bar(){};

La .prototypeproprietà contiene un oggetto a cui verrà assegnato b.[[Prototype]]quando lo fai var b = new Bar. Puoi facilmente esaminare questo:

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

Uno dei .prototypes più importanti è quello Object.prototype . Questo prototipo contiene l'oggetto prototipo che [[Prototype]]contengono tutte le catene. Su di esso sono definiti tutti i metodi disponibili per i nuovi oggetti:

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

Ora, poiché .prototypeè un oggetto, ha una [[Prototype]]proprietà. Quando non si apportano le assegnazioni per Function.prototypei .prototype's [[Prototype]]punti all'oggetto prototipo ( Object.prototype). Questo viene eseguito automaticamente ogni volta che crei una nuova funzione.

In questo modo, ogni volta che new Bar;si crea la catena di prototipi, si ottiene tutto ciò che è stato definito Bar.prototypee tutto è stato definito su Object.prototype:

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

Quando fai assegnamenti a Function.prototypetutto ciò che stai facendo, estendi la catena del prototipo per includere un altro oggetto. È come un inserimento in una lista concatenata.

Ciò altera sostanzialmente la [[Prototype]]catena consentendo le proprietà definite sull'oggetto assegnato Function.prototypea essere visto da qualsiasi oggetto creato dalla funzione.

[1: Ciò non confonderà nessuno; reso disponibile tramite la __proto__proprietà in molte implementazioni.
[2]: Tutti tranne null.


Considera il seguente keyValueStoreoggetto:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Posso creare una nuova istanza di questo oggetto facendo questo:

kvs = keyValueStore.create();

Ogni istanza di questo oggetto avrebbe le seguenti proprietà pubbliche:

  • data
  • get
  • set
  • delete
  • getLength

Ora, supponiamo di creare 100 istanze di questo keyValueStoreoggetto. Anche se get, set, delete, getLengthfarà la stessa cosa per ciascuno di questi 100 casi, ogni istanza ha la propria copia di questa funzione.

Ora, immaginate se si potrebbe avere solo un singolo get, set, deletee getLengthla copia, e ogni istanza avrebbe riferimento che la stessa funzione. Questo sarebbe meglio per le prestazioni e richiede meno memoria.

È qui che entrano i prototipi. Un prototipo è un "progetto" di proprietà ereditate ma non copiate dalle istanze. Questo significa che esiste solo una volta in memoria per tutte le istanze di un oggetto ed è condiviso da tutte queste istanze.

Ora, considera di keyValueStorenuovo l' oggetto. Potrei riscriverlo in questo modo:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Questo è ESATTAMENTE uguale alla versione precedente keyValueStoredell'oggetto, tranne per il fatto che tutti i suoi metodi sono ora inseriti in un prototipo. Ciò significa che tutte le 100 istanze ora condividono questi quattro metodi invece di avere ciascuno la propria copia.


Ho trovato utile spiegare la "catena del prototipo" come convenzione ricorsiva quando obj_n.prop_Xviene fatto riferimento:

se obj_n.prop_Xnon esiste, controlla obj_n+1.prop_Xdoveobj_n+1 = obj_n.[[prototype]]

Se prop_Xfinalmente si trova nell'oggetto prototipo k-th, allora

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

Puoi trovare un grafico della relazione degli oggetti Javascript in base alle loro proprietà qui:

http://jsobjects.org


Lascia che ti dica la mia comprensione dei prototipi. Non ho intenzione di confrontare l'eredità qui con altre lingue. Vorrei che le persone smettessero di paragonare le lingue e capissero solo la lingua. Comprendere i prototipi e l'eredità prototipale è così semplice, come ti mostrerò di seguito.

Il prototipo è come un modello, in base al quale si crea un prodotto. Il punto cruciale da capire è che quando si crea un oggetto usando un altro oggetto come prototipo, il collegamento tra il prototipo e il prodotto è duraturo. Per esempio:

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

Ogni oggetto contiene una proprietà interna chiamata [[prototype]], a cui è possibile accedere dalla Object.getPrototypeOf()funzione. Object.create(model)crea un nuovo oggetto e imposta la sua proprietà [[prototype]] al modello dell'oggetto . Quindi quando lo fai Object.getPrototypeOf(product), otterrai il modello dell'oggetto .

Le proprietà nel prodotto sono gestite nel modo seguente:

  • Quando si accede a una proprietà per leggere solo il suo valore, viene visualizzato nella catena dell'ambito. La ricerca della variabile inizia dal prodotto verso l' alto fino al suo prototipo. Se tale variabile viene trovata nella ricerca, la ricerca viene interrotta proprio lì e il valore viene restituito. Se non è possibile trovare una variabile di questo tipo nella catena di ambito, viene restituito undefined.
  • Quando una proprietà viene scritta (alterata), la proprietà viene sempre scritta sull'oggetto del prodotto . Se il prodotto non ha già una proprietà di questo tipo, viene creato e scritto in modo implicito.

Tale collegamento di oggetti che utilizzano la proprietà prototipo è chiamato ereditarietà prototipale. Lì, è così semplice, d'accordo?


Mi piacciono sempre le analogie quando si tratta di capire questo tipo di cose. "L'ereditarietà prototipale" è piuttosto confusa rispetto all'ereditarietà delle basse frequenze a mio parere, anche se i prototipi sono un paradigma molto più semplice. In effetti con i prototipi, non c'è davvero alcuna eredità, quindi il nome in sé e per sé è fuorviante, è più un tipo di "delega".

Immagina questo ....

Sei al liceo, e sei in classe e fai un quiz che è previsto oggi, ma non hai una penna per compilare le tue risposte. Doh!

Sei seduto accanto al tuo amico Finnius, che potrebbe avere una penna. Tu chiedi, e lui si guarda attorno senza successo, ma invece di dire "Non ho una penna", è un buon amico che controlla con l'altro suo amico Derp se ha una penna. Derp ha infatti una penna di riserva e la restituisce a Finnius, che la consegna a te per completare il tuo quiz. Derp ha affidato la penna a Finnius, che ti ha delegato la penna per l'uso.

Ciò che è importante qui è che Derp non ti dà la penna perché non hai una relazione diretta con lui.

Questo è un esempio semplificato di come funzionano i prototipi, in cui viene ricercato un albero di dati per la cosa che stai cercando.



un altro schema che mostra le relazioni __proto__ , prototipo e costruttore :





prototype-oriented