__proto__ VS. prototipo in JavaScript


785

Questa figura mostra di nuovo che ogni oggetto ha un prototipo. La funzione di costruzione Foo ha anche il suo __proto__che è Function.prototype e che a sua volta fa riferimento anche tramite __proto__Object.prototype tramite la sua proprietà. Quindi, ripeti, Foo.prototype è solo una proprietà esplicita di Foo che si riferisce al prototipo di oggetti bec.

var b = new Foo(20);
var c = new Foo(30);

Quali sono le differenze tra __proto__e prototype?

inserisci qui la descrizione dell'immagine

La cifra è stata presa da dmitrysoshnikov.com .



5
Penso che il top-down o il bottom-up sia una questione di preferenza. In realtà lo preferisco in questo modo, quindi posso rintracciare il diagramma finché non trovo da dove proviene qualcosa.
Mike Lippert,

1
Mi piace come JavaScript utilizza l'ereditarietà prototipica per risolvere y.constructor in y .__ proto __. Constructor. Mi piace anche come Object.prototype si collochi al vertice della catena di ereditarietà prototipica con Object.prototype .__ proto__ impostato su null. Mi piace anche come il diagramma comporti una visualizzazione concettuale a tre colonne di come il programmatore pensa agli oggetti come 1. istanze, 2. costruttori, 3. prototipi che i costruttori associano a tali istanze quando vengono istanziati tramite la nuova parola chiave.
John Sonderson,

Il diagramma ha immediatamente senso dopo aver visto qualcosa come youtube.com/watch?v=_JJgSbuj5VI , a proposito
mlvljr

E ora, mentre ho letto le risposte, mi sento in dovere di raccomandare davvero il video sopra, in quanto ha una spiegazione cristallina (e non WTFy) di quello che sta succedendo :)
mlvljr

Risposte:


766

__proto__è l'oggetto effettivo utilizzato nella catena di ricerca per risolvere i metodi, ecc. prototypeè l'oggetto utilizzato per creare __proto__quando si crea un oggetto con new:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

239
Ah! Quindi prototypenon è disponibile sulle istanze stesse (o altri oggetti), ma solo sulle funzioni del costruttore.
rvighne,

43
@rvighne: prototypeè disponibile solo sulle funzioni dal momento che sono derivati da Function, Functione Objectma in qualsiasi altra cosa non lo è. Tuttavia, __proto__è disponibile ovunque.
Tarik,

19
Così __proto__è l'oggetto reale che viene salvato e utilizzato come prototipo mentre Myconstructure.prototypeè solo un progetto per il __proto__quale, infatti, l'oggetto reale viene salvato e utilizzato come prototipo. Quindi myobject.prototypenon sarebbe una proprietà dell'oggetto reale perché è solo una cosa temporanea usata dalla funzione di costruzione per delineare come myobject.__proto__dovrebbe essere.
Alex_Nabu,

9
È corretto affermare che la __proto__proprietà di un oggetto è un puntatore alla prototypeproprietà della funzione di costruzione dell'oggetto ? ie foo .__ proto__ === foo.constructor.prototype
Niko Bellic

10
@Alex_Nabu Non proprio. newCar.__proto__ IS Car.prototype , non un'istanza di Car.prototype. Mentre Car.protoype IS è un'istanza di un object. Car.prototypeNon è qualcosa che dà newCarqualsiasi proprietà o struttura, semplicemente E ' il prossimo objecta newCar's catena di prototipi. Car.prototypenon è un temporaneo object. È quello objectche viene impostato come valore della __proto__proprietà di ogni nuova objects fatta usando Carcome a constructor. Se vuoi pensare a qualcosa come un progetto object, pensa a Carcome un modello per le nuove auto object.
seangwright,

336

prototypeè una proprietà di un oggetto Function. È il prototipo di oggetti costruiti da quella funzione.

__proto__è proprietà interna di un oggetto, che punta al suo prototipo. Gli standard attuali forniscono un Object.getPrototypeOf(O)metodo equivalente , sebbene lo standard di fatto __proto__sia più rapido.

Puoi trovare instanceofrelazioni confrontando una funzione prototypecon la __proto__catena di un oggetto e puoi interrompere queste relazioni cambiando prototype.

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;

Ecco Pointuna funzione di costruzione, costruisce un oggetto (struttura dati) in modo procedurale. myPointè un oggetto costruito da Point()così Point.prototypeviene salvato myPoint.__proto__in quel momento.


2
Inoltre, se si modifica la __proto__proprietà di un oggetto, cambia l'oggetto su cui vengono eseguite le ricerche del prototipo. Ad esempio, è possibile aggiungere un oggetto di metodi come funzione __proto__per avere una sorta di oggetto di istanza richiamabile.
kzh

myPoint .__ proto __. constructor.prototype == Point.prototype
Francisco

@kzh lol che mi ha dato risultati divertenti console.log(obj1.call) // [Function: call] obj1.call()// TypeError: obj1.call non è una funzione. L'ho fattoobj.__proto__ = Function.__proto__
abhisekp,

myFn.__proto__ = {foo: 'bar'}
kzh

Penso di avere il tuo punto.
ComicScrip,

120

La proprietà prototipo viene creata quando viene dichiarata una funzione.

Per esempio:

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

Person.prototypela proprietà viene creata internamente dopo aver dichiarato la funzione sopra. Molte proprietà possono essere aggiunte al Person.prototype che sono condivise dalle istanze Person create usando new Person ().

// adds a new method age to the Person.prototype Object.
Person.prototype.age = function(){return date-dob}; 

Vale la pena notare che Person.prototypeè Objectletterale per impostazione predefinita (può essere modificato in base alle esigenze).

Ogni istanza creata usando new Person()ha una __proto__proprietà che punta a Person.prototype. Questa è la catena che viene utilizzata per attraversare per trovare una proprietà di un oggetto particolare.

var person1 = new Person(somedate);
var person2 = new Person(somedate);

crea 2 istanze di Person, questi 2 oggetti possono chiamare ageil metodo di Person.prototypecome person1.age, person2.age.

Nell'immagine sopra della tua domanda, puoi vedere che Fooè un Function Objecte quindi ha un __proto__collegamento al Function.prototypequale a sua volta è un'istanza Objecte ha un __proto__collegamento a Object.prototype. Il link proto termina qui con __proto__il Object.prototypepuntamento a null.

Qualsiasi oggetto può avere accesso a tutte le proprietà nella sua catena protettiva come collegate da __proto__, formando così la base per l'eredità prototipale.

__proto__non è un modo standard per accedere alla catena di prototipi, è l'approccio standard ma simile da utilizzare Object.getPrototypeOf(obj).

Il codice seguente per l' instanceofoperatore offre una migliore comprensione:

L' instanceofoperatore Classe oggetto restituisce truequando un oggetto è un'istanza di una Classe, in particolare se Class.prototypesi trova nella catena protettiva di quell'oggetto, allora l'oggetto è un'istanza di quella Classe.

function instanceOf(Func){
  var obj = this;
  while(obj !== null){
    if(Object.getPrototypeOf(obj) === Func.prototype)
      return true;
    obj = Object.getPrototypeOf(obj);
  }
  return false;
}      

Il metodo sopra può essere chiamato come: instanceOf.call(object, Class)che restituisce vero se l'oggetto è un'istanza di Class.


2
Mi chiedevo perché l' prototypeoggetto è stato creato internamente in primo luogo? Si potrebbe semplicemente assegnare metodi statici all'oggetto funzione stesso. ad es function f(a){this.a = a}; f.increment = function(){return ++this.a}. Perché non è stato scelto in questo modo l'aggiunta dei metodi prototypeall'oggetto? Funzionerà se f.__proto__ = gg è la classe base.
abhisekp,

Forse l' prototypeoggetto è stato scelto per la condivisione perché solo le proprietà del costruttore della funzione esclusiva possono essere archiviate nell'oggetto costruttore della funzione.
abhisekp,

1
In realtà, sarebbe un disastro perché instanceofsi tradurrebbe in ({}) instanceof Function === trueun modo in cui non ci sarebbe modo di differenziare tra i prototipi se la prototypeproprietà viene rimossa.
abhisekp,

@abhisekp Cosa intendi con questo: "Funzionerà se f .__ proto__ = g dove g è la classe base." Non so se questo abbia un significato che non capisco, ma se dovessi aggiungere le proprietà e i metodi in quel modo, quando hai usato la newparola chiave per creare un'istanza, le proprietà e i metodi non sarebbero stati copiati al di sopra di.
doubleOrt

67

Un bel modo di pensarci è ...

prototypeviene utilizzato dalle constructor()funzioni. Avrebbe dovuto davvero essere chiamato qualcosa del genere "prototypeToInstall", dato che è quello che è.

ed __proto__è quel "prototipo installato" su un oggetto (che è stato creato / installato sull'oggetto da detta constructor()funzione)


2
L'ho votato a fondo, ma forse la ragione del downvote era perché l'affermazione "il prototipo viene utilizzato dalle funzioni di costruzione ()" potrebbe sembrare come se non avesse funzioni di costruzione, il che non è il caso, tuttavia a parte questo non è il nostro obiettivo ora si può notare che ogni funzione è potenzialmente un costruttore se chiamata con new ...
yoel halb

2
Si prega di cambiare " constructor()funzioni" in "funzioni di costruzione", poiché potrebbe esserci confusione con " __proto__.constructor()funzioni". Lo considero importante, in quanto il costruttore __proto __. Non viene effettivamente invocato quando newviene utilizzata una parola chiave.
Alexander Gonchiy,

1
L'affermazione che "il prototipo è usato dalle funzioni di costruzione () " racconta solo una parte di un fatto importante, ma lo ha detto in un modo che probabilmente porta i lettori a pensare che sia l'intero fatto. il prototipo viene creato internamente per ogni dichiarazione di funzione in Javascript, indipendentemente da come tale funzione verrà chiamata in futuro - con o senza la nuova parola chiave; il prototipo di una funzione dichiarata punta a un oggetto letterale.
Yiling

62

Per spiegare, creiamo una funzione

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

Quando JavaScript esegue questo codice, aggiunge la prototypeproprietà a a, la prototypeproprietà è un oggetto con due proprietà:

  1. constructor
  2. __proto__

Quindi quando lo facciamo

a.prototype ritorna

     constructor: a  // function definition
    __proto__: Object

Ora come puoi vedere constructornon è altro che la funzione astessa e __proto__punta al livello principale Objectdi JavaScript.

Vediamo cosa succede quando usiamo la afunzione con la newparola chiave.

var b = new a ('JavaScript');

Quando JavaScript esegue questo codice fa 4 cose:

  1. Crea un nuovo oggetto, un oggetto vuoto // {}
  2. Esso crea __proto__su be fa puntare ad a.prototypecosìb.__proto__ === a.prototype
  3. Esegue a.prototype.constructor(che è la definizione della funzione a) con l'oggetto appena creato (creato nel passaggio 1) come contesto (questo), quindi la nameproprietà passata come 'JavaScript' (che viene aggiunta a this) viene aggiunta all'oggetto appena creato.
  4. Restituisce l'oggetto appena creato in (creato nel passaggio 1) in modo che var bvenga assegnato all'oggetto appena creato.

Ora, se aggiungiamo a.prototype.car = "BMW"e facciamo b.car, appare l'output "BMW".

questo perché quando JavaScript ha eseguito questo codice ha cercato la carproprietà su b, non ha trovato JavaScript utilizzato b.__proto__(che è stato fatto puntare a 'a.prototype' nel passaggio # 2) e trova la carproprietà quindi restituisce "BMW".


2
1. constructornon ritorna a()! Ritorna a. 2. __proto__restituisce Object.prototype, non l'oggetto radice in Javascript.
doubleOrt

1
Questa è un'ottima risposta!
john-raymon,

+1 questa è la risposta migliore per spiegare che cos'è effettivamente il prototipo (un oggetto con due proprietà) e come Javascript esegue ogni pezzo di codice. Questa informazione è sorprendentemente difficile da trovare.
java-addict301,

53

Prototipo VS. __proto__ VS. [[Prototipo]]

Quando si crea una funzione, un oggetto proprietà chiamato prototipo viene creato automaticamente (non è stato creato da solo) e viene collegato all'oggetto funzione (il constructor).
Nota : questo nuovo oggetto prototipo punta anche o ha un collegamento interno-privato all'oggetto JavaScript nativo.

Esempio:

function Foo () {
    this.name = 'John Doe';
}

// Foo has an object property called prototype.
// prototype was created automatically when we declared the function Foo.
Foo.hasOwnProperty('prototype'); // true

// Now, we can assign properties and methods to it:
Foo.prototype.myName = function () {
    return 'My name is ' + this.name;
}

Se crei un nuovo oggetto Foousando la newparola chiave, stai fondamentalmente creando (tra le altre cose) un nuovo oggetto che ha un collegamento interno o privato al Fooprototipo della funzione di cui abbiamo discusso in precedenza:

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true


Il collegamento privato all'oggetto di quella funzione chiamato prototipo di parentesi doppie o giusto [[Prototype]]. Molti browser ci stanno fornendo un collegamento pubblico ad esso che ha chiamato __proto__!

Per essere più specifici, in __proto__realtà è una funzione getter che appartiene all'oggetto JavaScript nativo. Restituisce il collegamento prototipo interno-privato di qualunque sia l' thisassociazione (restituisce il [[Prototype]]di b):

b.__proto__ === Foo.prototype // true

Vale la pena notare che a partire da ECMAScript5, è anche possibile utilizzare il metodo getPrototypeOf per ottenere il collegamento privato interno:

Object.getPrototypeOf(b) === b.__proto__ // true


NOTA: questa risposta non intende coprire l'intero processo di creazione di nuovi oggetti o nuovi costruttori, ma per aiutare a comprendere meglio ciò che è __proto__, prototypee [[Prototype]]e come funziona.


2
@Taurus, fai clic sull'intestazione, porta al documento delle specifiche ECMAScript. Dai un'occhiata alla sezione 9 (Comportamenti di oggetti ordinari ed esotici) che lo spiega in modo molto più dettagliato.
Lior Elrom,

Penso che ci sia un errore qui: _ un nuovo oggetto che ha un collegamento interno o privato al prototipo della funzione Foo_ Vuoi dire: un nuovo oggetto che ha un collegamento interno o privato al prototipo della funzione Foo ?
Koray Tugay,

1
Grazie @KorayTugay! Sì, l'ho scritto male :) +1
Lior Elrom

31

Per chiarire un po 'oltre alle grandi risposte sopra:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

Le istanze hanno __proto__ , le classi hanno il prototipo .


12

In JavaScript, una funzione può essere utilizzata come costruttore. Ciò significa che possiamo creare oggetti da loro usando la nuova parola chiave. Ogni funzione di costruzione viene fornita con un oggetto incorporato incatenato con esse. Questo oggetto incorporato si chiama prototipo.Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

diagramma prototipo

  1. In primo luogo abbiamo creato un costruttore: function Foo(){}. Per essere chiari, Foo è solo un'altra funzione. Ma possiamo creare un oggetto da esso con la nuova parola chiave. Ecco perché la chiamiamo funzione di costruzione

  2. Ogni funzione ha una proprietà unica che si chiama proprietà prototipo. Quindi, la funzione Costruttore Fooha una proprietà prototipo che punta al suo prototipo, che è Foo.prototype(vedi immagine).

  3. Le funzioni del costruttore sono esse stesse una funzione che è un'istanza di un costruttore di sistema chiamato il costruttore [[Funzione]]. Quindi possiamo dire che function Fooè costruito da un costruttore [[Funzione]]. Quindi, __proto__del nostro Foo functionpunto puntiamo al prototipo del suo costruttore, che è Function.prototype.

  4. Function.prototypeè esso stesso nient'altro che un oggetto che è costruito da un altro costruttore di sistema chiamato [[Object]]. Quindi, [[Object]]è il costruttore di Function.prototype. Quindi, possiamo dire che Function.prototypeè un esempio di [[Object]]. Quindi, __proto__di Function.prototypepunti da Object.prototype.

  5. Object.prototypeè l'ultimo uomo in piedi nella catena di prototipi. Voglio dire, non è stato costruito. È già lì nel sistema. Quindi __proto__indica null.

  6. Ora veniamo alle istanze di Foo. Quando creiamo un'istanza usando new Foo(), crea un nuovo oggetto che è un'istanza di Foo. Ciò significa che Fooè il costruttore di questi casi. Qui abbiamo creato due istanze (xey). __proto__di xey quindi indica Foo.prototype.


Giusto per essere chiari: le istanze non hanno proprietà .prototype? Solo la funzione di costruzione è corretta? ... Quindi una differenza tra un'istanza e la sua funzione di costruzione è: le funzioni di costruzione hanno sia l'oggetto 1. proto 2. .prototype mentre le istanze hanno solo la proprietà .__ proto__ ... corretta?
Shaz,

@Shaz hai ragione. istanze usa il loro proto per accedere alla proprietà prototipo della loro funzione di costruzione.
AL-zami,

Ma perché perché quando scrivi: var car = Object.create (Veicolo); otterrai auto .__ proto__ = Veicolo MA hai anche una proprietà car.prototype che punta a Vehicle.prototype?
Shaz,

@shaz puoi fornire un jsfiddle in modo che io possa visualizzare la situazione?
AL-zami,

1
qui car.prototype è una proprietà ereditata. L'auto eredita la proprietà "prototipo" dalla funzione del veicolo. quindi car.prototype === vehicle.prototype. La proprietà "prototipo" è una proprietà sul veicolo. l'auto può accedervi attraverso la sua catena di prototipi. Spero che questo cancella la tua confusione
AL-zami,

8

Sommario:

La __proto__proprietà di un oggetto è una proprietà che si associa alla prototypefunzione di costruzione dell'oggetto. In altre parole:

instance.__proto__ === constructor.prototype // true

Questo è usato per formare la prototypecatena di un oggetto. La prototypecatena è un meccanismo di ricerca per le proprietà di un oggetto. Se si accede alla proprietà di un oggetto, JavaScript cercherà prima l'oggetto stesso. Se la proprietà non viene trovata lì, salirà fino a protochainquando non verrà trovata (o meno)

Esempio:

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

Person.prototype.age = 25;

const willem = new Person('Willem');

console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor

console.log(willem.age); // 25 doesn't find it at willem object but is present at prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

Il nostro primo log risulta a true, questo perché, come detto, la __proto__proprietà dell'istanza creata dal costruttore si riferisce alla prototypeproprietà del costruttore. Ricorda, in JavaScript, le funzioni sono anche oggetti. Gli oggetti possono avere proprietà e una proprietà predefinita di qualsiasi funzione è una proprietà denominata prototipo.

Quindi, quando questa funzione viene utilizzata come funzione di costruzione, l'oggetto istanziato da essa riceverà una proprietà chiamata __proto__. E questa __proto__proprietà si riferisce alla prototypeproprietà della funzione di costruzione (che per impostazione predefinita ha ogni funzione).

Perché è utile?

JavaScript ha un meccanismo quando si cercano proprietà su Objectscui si chiama 'ereditarietà prototipo' , ecco cosa fa sostanzialmente:

  • Innanzitutto, viene verificato se la proprietà si trova sull'oggetto stesso. In tal caso, questa proprietà viene restituita.
  • Se la proprietà non si trova sull'oggetto stesso, "scalerà la protochain". Praticamente esamina l'oggetto a cui fa riferimento la __proto__proprietà. Qui verifica se la proprietà è disponibile sull'oggetto a cui fa riferimento __proto__.
  • Se la proprietà non si trova __proto__sull'oggetto, salirà la __proto__catena, fino Objectall'oggetto.
  • Se non riesce a trovare la proprietà in nessun punto dell'oggetto e della sua prototypecatena, tornerà undefined.

Per esempio:

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

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);


7

Mi capita di apprendere il prototipo di You Don't Know JS: this & Object Prototypes , che è un libro meraviglioso per comprendere il design sottostante e chiarire così tante idee sbagliate (ecco perché sto cercando di evitare l'uso dell'eredità e cose del genere instanceof).

Ma ho la stessa domanda delle persone qui poste. Diverse risposte sono davvero utili e illuminanti. Mi piacerebbe anche condividere le mie comprensioni.


Cos'è un prototipo?

Gli oggetti in JavaScript hanno una proprietà interna, indicata nella specifica come [[Prototype]], che è semplicemente un riferimento a un altro oggetto. Quasi tutti gli oggetti hanno un nullvalore non valido per questa proprietà, al momento della loro creazione.

Come ottenere il prototipo di un oggetto?

tramite __proto__oObject.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype

Qual è il prototype?

prototypeè un oggetto creato automaticamente come proprietà speciale di una funzione , che viene utilizzato per stabilire la catena di delega (ereditarietà), nota anche come catena di prototipi.

Quando creiamo una funzione a, prototypeviene automaticamente creata come una proprietà speciale su ae salva il codice funzione come constructoron prototype.

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true

Mi piacerebbe considerare questa proprietà come il luogo in cui archiviare le proprietà (compresi i metodi) di un oggetto funzione. Questo è anche il motivo per cui funzioni di utilità in JS sono definiti come Array.prototype.forEach(), Function.prototype.bind(),Object.prototype.toString().

Perché enfatizzare la proprietà di una funzione ?

{}.prototype // undefined;
(function(){}).prototype // Object {constructor: function}

// The example above shows object does not have the prototype property.
// But we have Object.prototype, which implies an interesting fact that
typeof Object === "function"
var obj = new Object();

Così, Arary, Function, Objectsono tutte le funzioni. Devo ammettere che questo rinfresca la mia impressione su JS. So che le funzioni sono di prima classe in JS, ma sembra che sia basato su funzioni.

Qual è la differenza tra __proto__e prototype?

__proto__un riferimento funziona su ogni oggetto per fare riferimento alla sua [[Prototype]]proprietà.

prototypeè un oggetto creato automaticamente come proprietà speciale di una funzione , che viene utilizzato per memorizzare le proprietà (compresi i metodi) di un oggetto funzione.

Con questi due, potremmo mappare mentalmente la catena di prototipi. Come questa immagine illustra:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true

7

 Prototipo JavaScript vs __prototype__

'use strict'
function A() {}
var a = new A();
class B extends A {}
var b = new B();
console.log('====='); // =====
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true

In JavaScript, ogni oggetto (anche la funzione è oggetto!) Ha una __proto__proprietà, la proprietà fa riferimento al suo prototipo.

Quando utilizziamo l' newoperatore con un costruttore per creare un nuovo oggetto, la __proto__proprietà del nuovo oggetto verrà impostata con la prototypeproprietà del costruttore , quindi il costruttore verrà chiamato dal nuovo oggetto, in quel processo "questo" sarà un riferimento al nuovo oggetto nell'ambito del costruttore, restituisce infine il nuovo oggetto.

Il prototipo del costruttore è __proto__proprietà, la prototypeproprietà del costruttore è il lavoro con l' newoperatore.

Il costruttore deve essere una funzione, ma la funzione non è sempre costruttore anche se ha prototypeproprietà.

La catena di prototipi in realtà è __proto__proprietà dell'oggetto per fare riferimento al suo prototipo e __proto__proprietà del prototipo per fare riferimento al prototipo del prototipo, e così via, fino a fare riferimento alla __proto__proprietà del prototipo dell'Oggetto che è riferimento a null.

Per esempio:

console.log(a.constructor === A); // true
// "a" don't have constructor,
// so it reference to A.prototype by its ``__proto__`` property,
// and found constructor is reference to A

[[Prototype]]e la __proto__proprietà in realtà è la stessa cosa.

Possiamo usare il metodo getPrototypeOf di Object per ottenere il prototipo di qualcosa.

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

Qualsiasi funzione che abbiamo scritto può essere utilizzata per creare un oggetto con l' newoperatore, quindi chiunque di quelle funzioni può essere un costruttore.


6

Un altro buon modo per capirlo:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.prototype; Object.prototype in return is what foo.__proto__ links to. 
*/
console.log(foo.constructor.prototype === foo.__proto__);
// this proves what the above comment proclaims: Both statements evaluate to true.
console.log(foo.__proto__ === Object.prototype);
console.log(foo.constructor.prototype === Object.prototype);

Solo dopo IE11 __proto__è supportato. Prima di quella versione, come IE9, è possibile utilizzare il constructorper ottenere il __proto__.


Solo che lo scriverei al contrario: foo .__ proto__ === foo.constructor.prototype
epeleg

6

prototipo

il prototipo è una proprietà di una funzione. È il progetto per la creazione di oggetti usando quella funzione (costruttore) con una nuova parola chiave.

__proto__viene utilizzato nella catena di ricerca per risolvere metodi, proprietà. quando viene creato un oggetto (utilizzando la funzione di costruzione con una nuova parola chiave), __proto__viene impostato su (Funzione) Funzione.prototipo

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype

Ecco la mia (immaginaria) spiegazione per cancellare la confusione:

Immagina che ci sia una classe immaginaria (blueprint / coockie cutter) associata alla funzione. Quella classe immaginaria viene utilizzata per istanziare oggetti. prototypeè il meccanismo di estensione (metodo di estensione in C # o Swift Extension) per aggiungere elementi a quella classe immaginaria.

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

Quanto sopra può essere immaginato come:

// imaginary class
class Robot extends Object{

    static prototype = Robot.class  
    // Robot.prototype is the way to add things to Robot class
    // since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype

    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 

Così,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

Ora aggiungendo metodo a prototypeRobot:

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};
// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

Quanto sopra può essere immaginato come estensione della classe Robot:

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

Che a loro volta,

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

    // added by prototype (as like C# extension method)
    function move(x, y){ 
        Robot.position.x = x; Robot.position.y = y
    };
}

sto ancora pensando a nomi __proto__e prototipi più coerenti . forse prototipo ed eredità?
Dmitry

Direi, prototypeed __proto__entrambi dovrebbero essere evitati. Adesso abbiamo lezione e mi piace OOP.
Hassan Tareq,

il problema è che la classe è relativamente nuova e non è supportata da motori davvero convenienti come microsoft JScript (bello avere quando si lavora su C e necessita di un motore di script veloce e sporco che è sempre lì), e nashorn javascript (che viene fornito con tutto nuove installazioni Java sotto jjs ed è un bel modo di mettere Java in un ambiente dinamico puro in cui non è necessario ricompilare costantemente le cose). Il fatto è che se la classe fosse zucchero, non sarebbe un problema, ma non lo è, offre cose che sono impossibili senza di loro nelle versioni js precedenti. Come estendere "Funzione".
Dmitry

Alla fine avremo supporto. Sono uno sviluppatore di back-end, quindi non ho problemi, codice raramente in js.
Hassan Tareq,

ed ereditare membri statici in modo tale che l'aggiunta di nuovi / rimozione di membri statici dal genitore venga notato dal figlio (cosa che non riesco a pensare a un modo di fare su JScript, che non offre Object.assign / __ proto __ / getPrototypeOf, quindi tu armeggiare con il root Object.prototype per simularlo)
Dmitry

4

Per dirla semplicemente:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true

Ciò consente di associare proprietà a X.prototype DOPO che gli oggetti di tipo X sono stati istanziati e avranno comunque accesso a tali nuove proprietà tramite il riferimento __proto__ che il motore Javascript utilizza per percorrere la catena del prototipo.


4

Prototype o Object.prototype è una proprietà di un oggetto letterale. Rappresenta l' oggetto prototipo Object che è possibile ignorare per aggiungere ulteriori proprietà o metodi lungo la catena del prototipo.

__proto__ è una proprietà accessor (funzione get and set) che espone il prototipo interno di un oggetto attraverso il quale si accede.

Riferimenti:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
  2. http://www.w3schools.com/js/js_object_prototypes.asp

  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto


Object.prototypenon è una proprietà di un oggetto letterale, provare a stampare {}.prototyperendimenti indefiniti; tuttavia, è possibile accedervi tramite {}.__proto__, che ritorna Object.prototype.
doubleOrt

3

Lo so, sono in ritardo, ma fammi provare a semplificarlo.

Diciamo che c'è una funzione

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);

La funzione Foo avrà un oggetto prototipo collegato. Quindi, ogni volta che creiamo una funzione in JavaScript, ha sempre un oggetto prototipo collegato ad essa.

Ora andiamo avanti e creiamo due oggetti usando la funzione Foo.

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);
  1. Ora abbiamo due oggetti, l'oggetto a e l'oggetto b. Entrambi sono creati usando il costruttore Foo. Tieni presente che costruttore è solo una parola qui.
  2. Gli oggetti aeb hanno entrambi una copia della proprietà message.
  3. Questi due oggetti aeb sono collegati all'oggetto prototipo del costruttore Foo.
  4. Sugli oggetti aeb, possiamo accedere al prototipo Foo usando la proprietà proto in tutti i browser e in IE possiamo usare Object.getPrototypeOf (a) o Object.getPrototypeOf (b)

Ora, Foo.prototype, a. proto e b. proto all indica lo stesso oggetto.

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;

tutto quanto sopra sarebbe tornato vero.

Come sappiamo, in JavaScript le proprietà possono essere aggiunte in modo dinamico. Possiamo aggiungere proprietà all'oggetto

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 

Come vedi, abbiamo aggiunto il metodo Greet () in Foo.prototype ma è accessibile in a e b o in qualsiasi altro oggetto che viene costruito usando Foo.

Durante l'esecuzione di a.Greet (), JavaScript cercherà per prima cosa nell'oggetto Proprietà nell'elenco di proprietà. Non trovandolo, salirà nella catena protettiva di a. Dal. proto e Foo.prototype è lo stesso oggetto, JavaScript troverà il metodo Greet () e lo eseguirà.

Mi auguro, ora prototipo e proto è semplificata un po '.


3

Esempio esplicativo:

function Dog(){}
Dog.prototype.bark = "woof"

let myPuppie = new Dog()

ora myPupppie ha __proto__proprietà che puntano a Dog.prototype.

> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}

ma myPuppie NON ha una proprietà prototipo.

> myPuppie.prototype
>> undefined

Quindi, __proto__di mypuppie è il riferimento alla proprietà .prototype della funzione di costruzione che è stata utilizzata per creare un'istanza di questo oggetto (e l'oggetto myPuppie corrente ha una relazione "delegati a" con questo __proto__oggetto), mentre la proprietà .prototype di myPuppie è semplicemente assente (poiché non l'abbiamo impostato).

Buona spiegazione per MPJ qui: proto vs prototipo - Creazione di oggetti in JavaScript


3

Ho realizzato per me un piccolo disegno che rappresenta il seguente frammento di codice:

var Cat = function() {}
var tom = new Cat()

Comprensione di __proto__ e prototipo

Ho un background OO classico, quindi è stato utile rappresentare la gerarchia in questo modo. Per aiutarti a leggere questo diagramma, tratta i rettangoli nell'immagine come oggetti JavaScript. E sì, anche le funzioni sono oggetti. ;)

Gli oggetti in JavaScript hanno proprietà ed __proto__è solo uno di questi.

L'idea alla base di questa proprietà è quella di puntare all'oggetto antenato nella gerarchia (ereditaria).

L'oggetto radice in JavaScript è Object.prototypee tutti gli altri oggetti sono i discendenti di questo. La __proto__proprietà dell'oggetto root è null, che rappresenta la fine della catena di ereditarietà.

Noterai che prototypeè una proprietà delle funzioni. Catè una funzione, ma anche Functione Objectsono funzioni (native). tomnon è una funzione, quindi non ha questa proprietà.

L'idea alla base di questa proprietà è quella di puntare a un oggetto che verrà utilizzato nella costruzione, cioè quando si chiama l' newoperatore su quella funzione.

Si noti che gli oggetti prototipo (rettangoli gialli) hanno un'altra proprietà chiamata constructorche punta al rispettivo oggetto funzione. Per ragioni di brevità questo non è stato rappresentato.

In effetti, quando creiamo l' tomoggetto con new Cat(), l'oggetto creato avrà la __proto__proprietà impostata prototypesull'oggetto della funzione di costruzione.

Alla fine, giochiamo un po 'con questo diagramma. Le seguenti affermazioni sono vere:

  • tom.__proto__la proprietà punta allo stesso oggetto di Cat.prototype.

  • Cat.__proto__punta Function.prototypeall'oggetto, proprio come Function.__proto__e Object.__proto__fare.

  • Cat.prototype.__proto__e tom.__proto__.__proto__punta allo stesso oggetto e cioè Object.prototype.

Saluti!


Molto ben spiegato!
StackOverflow UI

@theshinylight, tom.__proto__e Cat.prototypesono rigorosamente uguali, quindi, tom.__proto__ === Cat.prototype e Cat.prototype === tom.__proto__sono vere. Quindi, cosa intendevi con la freccia nell'immagine ??
aXuser264,

La freccia nera (se ti riferisci ad essa) non ha alcun significato particolare, oltre alla proprietà dell'oggetto. Così prototypeè la proprietà Catdell'oggetto (dalla tua domanda).
theshinylight

2

DEFINIZIONI

(il numero tra parentesi () è un "collegamento" al codice scritto sotto)

prototype- un oggetto costituito da:
=> funzioni (3) di questo particolare ConstructorFunction.prototype(5) che sono accessibili da ciascun oggetto (4) creato o da creare tramite questa funzione di costruzione (1)
=> la funzione di costruzione stessa (1 )
=> __proto__di questo particolare oggetto (oggetto prototipo)

__proto__(dandor proto?) - un collegamento TRA qualsiasi oggetto (2) creato tramite una particolare funzione di costruzione (1) E le proprietà dell'oggetto prototipo (5) di quel costruttore CHE consente a ciascun oggetto creato (2) di avere accesso alle funzioni del prototipo e metodi (4) ( __proto__per impostazione predefinita è incluso in ogni singolo oggetto in JS)

CHIARIMENTO DEL CODICE

1.

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

2.

    var John = new Person(‘John’, 37);
    // John is an object

3.

    Person.prototype.getOlder = function() {
        this.age++;
    }
    // getOlder is a key that has a value of the function

4.

    John.getOlder();

5.

    Person.prototype;

1

Proverò una spiegazione di 4 ° grado:

Le cose sono molto semplici A prototypeè un esempio di come dovrebbe essere costruito qualcosa. Così:

  • Sono un functione costruisco nuovi oggetti simili al mioprototype

  • Sono un objecte sono stato costruito usando il mio __proto__come esempio

prova :

function Foo() { }

var bar = new Foo()

// `bar` is constructed from how Foo knows to construct objects
bar.__proto__ === Foo.prototype // => true

// bar is an instance - it does not know how to create objects
bar.prototype // => undefined

1
No, né prototypené uno __proto__viene utilizzato in qualsiasi momento come progetto o giù di lì per creare qualsiasi oggetto. Questo è un mito introdotto dalla classsintassi sfocata e dai suoi predecessori. Come dice il post di risposta, viene utilizzato solo per la catena di ricerca e in caso di prototypeidentificazione constructorutilizzato new(che fa parte di quel meccanismo di pretesa di essere di classe che confonde molti utenti tra cui me).
Christof Kälin,

Il primo punto dovrebbe essere "Sono una funzione e costruisco nuovi oggetti che delegheranno al mio prototipo"
Nitin Jadhav,

1

Ogni funzione che crei ha una proprietà chiamata prototypee inizia la sua vita come un oggetto vuoto. Questa proprietà è inutile fino a quando non si utilizza questa funzione come funzione di costruzione, ad esempio con la parola chiave "new".

Questo è spesso confuso con la __proto__proprietà di un oggetto. Alcuni potrebbero confondersi e, a parte il fatto che la prototypeproprietà di un oggetto potrebbe ottenere la proto di un oggetto. Ma questo non è il caso. prototypeviene utilizzato per ottenere l' __proto__oggetto creato da un costruttore di funzioni.

Nell'esempio sopra:

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

var eve = new Person("Eve");

console.log(eve.__proto__ == Person.prototype) // true
// this is exactly what prototype does, made Person.prototype equal to eve.__proto__

Spero abbia senso.


1
prototypenon viene utilizzato per creare il __proto__di un oggetto. __proto__, quando vi si accede, fornisce semplicemente un riferimento prototypeall'oggetto.
doubleOrt

1

Che dire dell'utilizzo __proto__di metodi statici?

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined

Questo è esattamente il motivo per cui una risposta a " __proto__VS. prototypein JavaScript" ?
Andreas,

è buono o che dire di Foo.collection.push (questo) Foo.count ++
Selva Ganapathi

1

(function(){ 
      let a = function(){console.log(this.b)};
      a.prototype.b = 1;
      a.__proto__.b = 2;
      let q = new a();
      console.log(a.b);
      console.log(q.b) 
    })()

Prova questo codice per capire


1

Esiste un solo oggetto utilizzato per il concatenamento prototipo. Questo oggetto ha ovviamente un nome e un valore: __proto__è il suo nome ed prototypeè il suo valore. È tutto.

per renderlo ancora più facile da capire, guarda il diagramma nella parte superiore di questo post (Diagramma di dmitry soshnikov), non troverai mai __proto__punti a qualcos'altro oltre prototypeal suo valore.

L'essenza è questa: __proto__è il nome che fa riferimento all'oggetto prototipo ed prototypeè l'oggetto prototipo effettivo.

È come dire:

let x = {name: 'john'};

xè il nome dell'oggetto (puntatore) ed {name: 'john'}è l'oggetto reale (valore dei dati).

NOTA: questo è solo un suggerimento enormemente semplificato su come sono correlati ad alto livello.

Aggiornamento: ecco un semplice esempio javascript concreto per una migliore illustrazione:

let x = new String("testing") // Or any other javascript object you want to create

Object.getPrototypeOf(x) === x.__proto__; // true

Ciò significa che quando Object.getPrototypeOf(x)ci ottiene il valore effettivo della x(che è il suo prototipo), è esattamente ciò che il __proto__di xsta indicando. Pertanto __proto__punta davvero al prototipo di x. Quindi __proto__riferimenti x(puntatore di x), ed prototypeè il valore di x(il suo prototipo).

Spero sia un po 'chiaro ora.


1

Questa è una domanda molto importante relativa a chiunque voglia comprendere l'eredità prototipica. Da quanto ho capito, il prototipo viene assegnato per impostazione predefinita quando un oggetto viene creato con un nuovo da una funzione perché Function ha un oggetto prototipo per definizione:

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]

Quando creiamo un oggetto ordinario senza nuovo, cioè esplicitamente da una funzione, non ha un prototipo ma ha un proto vuoto a cui può essere assegnato un prototipo.

var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

Possiamo usare Object.create per collegare esplicitamente un oggetto.

// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`

0

__proto__è la base da costruire prototypee una funzione di costruzione, ad esempio: function human(){}ha la prototypequale è condivisa tramite __proto__nella nuova istanza della funzione di costruzione. Una lettura più dettagliata qui


@Derick Daniel: non sono sicuro del motivo per cui hai votato, ma la modifica che hai apportato non era che stavo cercando di trasmettere. Modificato ulteriormente per maggiore spazio :).
Jyoti Duhan,

Jyoti, non ho votato in giù la tua risposta, l'ha fatto qualcun altro, l'ho appena modificata :)
Freelancer

0

Come questo giustamente affermato

__proto__è l'oggetto effettivo utilizzato nella catena di ricerca per risolvere i metodi, ecc. prototype è l'oggetto che viene utilizzato per creare __proto__quando si crea un oggetto con new:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

Possiamo inoltre notare che la __proto__proprietà di un oggetto creato usando il costruttore di funzioni punta verso la posizione di memoria puntata dalla proprietà prototipo di quel rispettivo costruttore.

Se cambiamo la posizione di memoria del prototipo della funzione di costruzione, l' __proto__oggetto derivato continuerà comunque a puntare verso lo spazio degli indirizzi originale. Pertanto, per rendere disponibile la proprietà comune lungo la catena di ereditarietà, aggiungere sempre la proprietà al prototipo della funzione di costruzione , anziché reinizializzarla (che cambierebbe il suo indirizzo di memoria).

Considera il seguente esempio:

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25

-1

la mia comprensione è: __proto__ e prototipo sono tutti serviti per la tecnica della catena prototipo. la differenza è che le funzioni denominate con trattino basso (come __proto__) non mirano affatto agli sviluppatori invocati esplicitamente. in altre parole, sono solo per alcuni meccanismi come ereditari ecc. sono "back-end". ma le funzioni denominate senza carattere di sottolineatura sono progettate per essere invocate in modo esplicito, sono "front-end".


3
Ci sono più __proto__e prototype, oltre alla semplice convenzione di denominazione. Possono o meno indicare lo stesso oggetto. Vedi la risposta di @zyklus.
Demisx,

1
@demisx ovviamente hai detto che è giusto, ma la mia opinione è che la differenza di nome ha messo in luce il contrasto della funzionalità.
Beicai,

Non è sufficiente affermare "secondo la tua comprensione", soprattutto quando altre buone risposte sono state fornite prima ...
ProfNandaa

-3

!!! QUESTA È LA MIGLIORE SPIEGAZIONE NEL MONDO !!!!!

var q = {}
var prototype = {prop: 11}

q.prop // undefined
q.__proto__ = prototype
q.prop // 11

nei costruttori di funzioni il motore javascript lo chiama q.__proto__ = prototypeautomaticamente quando scriviamo new Classe nel __proto__set di oggetti di scenaClass.prototype

function Class(){}
Class.prototype = {prop: 999} // set prototype as we need, before call new

var q = new Class() // q.__proto__ = Class.prototype
q.prop // 999

Godere %)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.