Questo è un modello di oggetto basato su prototipo molto semplice che verrebbe considerato come un campione durante la spiegazione, senza ancora commenti:
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 concetto di prototipo.
1- Come funzionano effettivamente le funzioni JavaScript:
Per fare il primo passo dobbiamo capire come funzionano effettivamente le funzioni JavaScript, come una funzione di classe come usare la this
parola chiave in essa o semplicemente come una normale funzione con i suoi argomenti, cosa fa e cosa restituisce.
Diciamo che vogliamo creare un Person
modello a oggetti. ma in questo passaggio ci proverò fare la stessa cosa esatta senza l'utilizzo prototype
e new
parola chiave .
Quindi in questo passaggio functions
,objects
e this
parola chiave, siamo tutto ciò che abbiamo.
La prima domanda sarebbe comethis
parola chiave potrebbe essere utile senza usare la new
parola 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 adesso senza usare la new
parola chiave come potremmo usare queste funzioni. Quindi JavaScript ha 3 modi diversi per farlo:
un. il primo modo è solo quello di chiamare la funzione come una normale funzione:
Person("George");
getName();//would print the "George" in the console
in questo caso, questo sarebbe l'oggetto di contesto corrente, che di solito è il globale window
oggetto nel browser o GLOBAL
inNode.js
. Significa che avremmo, window.name nel browser o GLOBAL.name in Node.js, con "George" come valore.
b. Noi possiamo collegarli a un oggetto, come le sue proprietà
- Il modo più semplice per farlo è modificare l' person
oggetto vuoto , come:
person.Person = Person;
person.getName = getName;
in questo modo possiamo chiamarli come:
person.Person("George");
person.getName();// -->"George"
e ora l' person
oggetto è come:
Object {Person: function, getName: function, name: "George"}
- L'altro modo per associare una proprietà a un oggetto è usare quello prototype
di quell'oggetto che può essere trovato in qualsiasi oggetto JavaScript con il nome di __proto__
, e ho provato a spiegarlo un po 'nella 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 effettivamente facendo è modificare il Object.prototype
, perché ogni volta che creiamo un oggetto JavaScript usando i valori letterali ( { ... }
), viene creato in base a Object.prototype
, il che significa che viene collegato all'oggetto appena creato come un attributo chiamato__proto__
, quindi se lo cambiamo , come abbiamo fatto con il nostro precedente frammento di codice, tutti gli oggetti JavaScript verrebbero modificati, non è una buona pratica. Quindi quale potrebbe essere la migliore pratica ora:
person.__proto__ = {
Person: Person,
getName: getName
};
e ora altri oggetti sono in pace, ma non sembra ancora essere una buona pratica. Quindi abbiamo ancora un'altra soluzione, ma per usare questa soluzione dovremmo tornare a quella riga di codice in cui l' person
oggetto è stato creato ( var person = {};
) quindi cambiarlo come:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
quello che fa è creare un nuovo JavaScript Object
e allegare propertiesObject
al file__proto__
attributo. Quindi, per essere sicuro di poter fare:
console.log(person.__proto__===propertiesObject); //true
Ma il punto difficile qui è che hai accesso a tutte le proprietà definite nel __proto__
primo livello diperson
dell'oggetto (leggi la parte di riepilogo per maggiori dettagli).
come vedi usando uno di questi due modi this
significherebbe esattamente l' person
oggetto.
c. JavaScript ha un altro modo per fornire la funzione this
, che utilizza call o apply per invocare la funzione.
Il metodo apply () chiama una funzione con un dato valore e argomenti forniti come una matrice (o un oggetto simile a una matrice).
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 passi iniziali importanti per capire la funzionalità .prototype.
2- Come funziona il new
parola chiave?
questo è il secondo passo per capire la .prototype
funzionalità. Questo è 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 fare tutti i passi che JavaScript prende, senza usare la new
parola chiave e prototype
, quando usi la new
parola chiave. così quando lo facciamonew Person("George")
,Person
funzione funge da costruttore, cosa fa JavaScript, uno per uno:
un. prima di tutto crea un oggetto vuoto, sostanzialmente un hash vuoto come:
var newObject = {};
b. il prossimo passo che JavaScript fa è collegarlo 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];
}
JavaScript non associa effettivamente le proprietà definite nel prototipo. Il modo attuale è legato al concetto di catena prototipo.
un. & b. Invece di questi due passaggi puoi ottenere lo stesso risultato esatto 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 getName
funzione nel nostro my_person_prototype
:
newObject.getName();
c. quindi dà quell'oggetto al costruttore,
possiamo farlo con il nostro campione come:
Person.call(newObject, "George");
o
Person.apply(newObject, ["George"]);
quindi il costruttore può fare quello che vuole, perché questo all'interno di quel costruttore è l'oggetto che è stato appena creato.
ora il risultato finale prima di simulare gli altri passaggi: Object {name: "George"}
Sommario:
Fondamentalmente, quando usi la nuova parola chiave su una funzione, la stai invocando e quella funzione funge da costruttore, quindi quando dici:
new FunctionName()
JavaScript crea internamente un oggetto, un hash vuoto e quindi dà quell'oggetto al costruttore, quindi il costruttore può fare quello che vuole, perché questo all'interno di quel costruttore è l'oggetto che è stato appena creato e quindi ti dà quell'oggetto ovviamente se non hai utilizzato l'istruzione return nella tua funzione o se hai inserito un return undefined;
alla fine del corpo della tua funzione.
Quindi, quando JavaScript cerca una proprietà su un oggetto, la prima cosa che fa è cercare quella su quell'oggetto. E poi c'è una proprietà segreta [[prototype]]
che di solito ce l'abbiamo __proto__
e quella proprietà è ciò che JavaScript guarda dopo. E quando guarda attraverso __proto__
, per quanto sia di nuovo un altro oggetto JavaScript, ha il suo __proto__
attributo, va su e su fino a raggiungere il punto in cui il prossimo __proto__
è nullo. Il punto è l'unico oggetto in JavaScript che il suo __proto__
attributo è null è Object.prototype
object:
console.log(Object.prototype.__proto__===null);//true
ed è così che funziona l'ereditarietà in JavaScript.
In altre parole, quando hai una proprietà prototipo su una funzione e ne chiami una nuova su quella, dopo che JavaScript ha finito per guardare l'oggetto appena creato per le proprietà, andrà a guardare la funzione .prototype
ed è anche possibile che questo oggetto abbia il suo proprio prototipo interno. e così via.