Perché è necessario impostare il costruttore del prototipo?


294

Nella sezione sull'ereditarietà nell'articolo MDN Introduzione a Javascript orientato agli oggetti , ho notato che hanno impostato prototype.constructor:

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;  

Questo ha qualche scopo importante? Va bene ometterlo?


23
Sono contento che tu l'abbia chiesto: ieri ho letto la stessa documentazione ed ero curioso del ragionamento dietro l'impostazione esplicita del costruttore.
Wylie il

6
Ho appena dovuto sottolineare questo, questa domanda è ora collegata nell'articolo che hai collegato!
Marie,

7
nulla è necessaria
nothingisnecessary

1
Il subclass.prototype.constructorpunterà parent_classse non si scrive subclass.prototype.constructor = subclass; Cioè, l'utilizzo subclass.prototype.constructor()diretto produrrà un risultato imprevisto.
KuanYu Chu,

Risposte:


263

Non è sempre necessario, ma ha i suoi usi. Supponiamo di voler creare un metodo di copia sulla Personclasse base . Come questo:

// define the Person Class  
function Person(name) {
    this.name = name;
}  

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

// define the Student class  
function Student(name) {  
    Person.call(this, name);
}  

// inherit Person  
Student.prototype = Object.create(Person.prototype);

Cosa succede quando ne creiamo uno nuovo Studente lo copiamo?

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => false

La copia non è un'istanza di Student. Questo perché (senza controlli espliciti), non avremmo modo di restituire una Studentcopia dalla classe "base". Possiamo solo restituire a Person. Tuttavia, se avessimo ripristinato il costruttore:

// correct the constructor pointer because it points to Person  
Student.prototype.constructor = Student;

... quindi tutto funziona come previsto:

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => true

34
Nota: l' constructorattributo non ha alcun significato speciale in JS, quindi potresti anche chiamarlo bananashake. L'unica differenza è che il motore inizializza automaticamente constructorsu f.prototypeogni volta che si dichiara una funzione f. Tuttavia, può essere sovrascritto in qualsiasi momento.
user123444555621

58
@ Pumbaa80 - I ottenere risultati, ma il fatto che il motore inizializza automaticamente constructorsignifica che ha un significato speciale in JS, praticamente per definizione.
Wayne,

13
Voglio solo chiarire che il motivo per cui il comportamento che hai detto funziona è perché usi return new this.constructor(this.name);invece di return new Person(this.name);. Poiché this.constructorè la Studentfunzione (perché l'hai impostata con Student.prototype.constructor = Student;), la copyfunzione finisce per chiamare la Studentfunzione. Non sono sicuro di quale fosse la tua intenzione con il //just as badcommento.
CEGRD,

12
@lwburk cosa intendi con "// altrettanto male"?
CEGRD,

6
Penso di averlo capito. Ma cosa succede se il Studentcostruttore avesse aggiunto un argomento aggiuntivo come Student(name, id):? Dobbiamo quindi sovrascrivere la copyfunzione, chiamare la Personversione al suo interno e quindi copiare anche la idproprietà aggiuntiva ?
snapfractalpop

76

Questo ha qualche scopo importante?

Sì e no.

In ES5 e precedenti, JavaScript stesso non utilizzava constructornulla. Ha definito l'oggetto predefinito su una funzioneprototype proprietà di avrebbe e che si sarebbe riferito alla funzione, e basta . Nient'altro nelle specifiche ha fatto riferimento ad esso.

Ciò è cambiato in ES2015 (ES6), che ha iniziato a usarlo in relazione alle gerarchie ereditarie. Ad esempio, Promise#thenutilizza la constructorproprietà della promessa su cui la si chiama (tramite SpeciesConstructor ) quando costruisci la nuova promessa da restituire. È anche coinvolto in array di sottotipi (tramite ArraySpeciesCreate ).

Al di fuori del linguaggio stesso, a volte le persone lo userebbero quando provano a costruire funzioni generiche di "clone" o semplicemente in generale quando vogliono fare riferimento a ciò che credevano essere la funzione di costruzione dell'oggetto. La mia esperienza è che usarlo è raro, ma a volte le persone lo usano.

Va bene ometterlo?

È lì per impostazione predefinita, è sufficiente rimetterlo quando si sostituisce l'oggetto su una funzioneprototype proprietà di :

Student.prototype = Object.create(Person.prototype);

Se non lo fai:

Student.prototype.constructor = Student;

... quindi Student.prototype.constructoreredita da Person.prototype(presumibilmente) constructor = Person. Quindi è fuorviante. E, naturalmente, se stai eseguendo la sottoclasse di qualcosa che lo utilizza (come PromiseoArray ) e non utilizzando class¹ (che lo gestisce per te), ti consigliamo di impostarlo correttamente. Quindi in pratica: è una buona idea.

Va bene se non viene utilizzato nulla nel codice (o nel codice libreria utilizzato). Mi sono sempre assicurato che fosse correttamente cablato.

Ovviamente, con la classparola chiave ES2015 (aka ES6) , la maggior parte delle volte l'avremmo usata, non ce la facciamo più, perché è gestita per noi quando lo facciamo

class Student extends Person {
}

¹ "... se stai eseguendo la sottoclasse di qualcosa che lo usa (come Promiseo Array) e non usi class..."  - È possibile farlo, ma è un vero dolore (e un po 'sciocco). Devi usare Reflect.construct.


12

TLDR; Non super necessario, ma probabilmente aiuterà a lungo termine, ed è più preciso farlo.

NOTA: Molto modificato in quanto la mia risposta precedente è stata scritta in modo confuso e presentava alcuni errori a cui ho perso la fretta di rispondere. Grazie a coloro che hanno segnalato alcuni errori eclatanti.

Fondamentalmente, si tratta di collegare correttamente la sottoclasse in Javascript. Quando effettuiamo la sottoclasse, dobbiamo fare alcune cose funky per assicurarci che la delegazione prototipo funzioni correttamente, inclusa la sovrascrittura di un prototypeoggetto. La sovrascrittura di un prototypeoggetto include il constructor, quindi è necessario correggere il riferimento.

Vediamo rapidamente come funzionano le "classi" in ES5.

Supponiamo che tu abbia una funzione di costruzione e il suo prototipo:

//Constructor Function
var Person = function(name, age) {
  this.name = name;
  this.age = age;
}

//Prototype Object - shared between all instances of Person
Person.prototype = {
  species: 'human',
}

Quando chiami il costruttore per creare un'istanza, dì Adam:

// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);

La newparola chiave invocata con "Person" eseguirà sostanzialmente il costruttore Person con alcune righe di codice aggiuntive:

function Person (name, age) {
  // This additional line is automatically added by the keyword 'new'
  // it sets up the relationship between the instance and the prototype object
  // So that the instance will delegate to the Prototype object
  this = Object.create(Person.prototype);

  this.name = name;
  this.age = age;

  return this;
}

/* So 'adam' will be an object that looks like this:
 * {
 *   name: 'Adam',
 *   age: 19
 * }
 */

Se noi console.log(adam.species), la ricerca fallirà adamnell'istanza, e cercheremo la catena prototipo alla sua .prototype, che è Person.prototype- e Person.prototype ha una .speciesproprietà, quindi la ricerca riuscirà Person.prototype. Quindi registrerà 'human'.

Qui, Person.prototype.constructorindicherà correttamente Person.

Quindi ora la parte interessante, la cosiddetta "sottoclasse". Se vogliamo creare una Studentclasse, che è una sottoclasse della Personclasse con alcune modifiche aggiuntive, dovremo assicurarci che i Student.prototype.constructorpunti a Studente siano precisi.

Non lo fa da solo. Quando si esegue la sottoclasse, il codice è simile al seguente:

var Student = function(name, age, school) {
 // Calls the 'super' class, as every student is an instance of a Person
 Person.call(this, name, age);
 // This is what makes the Student instances different
 this.school = school
}

var eve = new Student('Eve', 20, 'UCSF');

console.log(Student.prototype); // this will be an empty object: {}

Chiamare new Student()qui restituirebbe un oggetto con tutte le proprietà che vogliamo. Qui, se controlliamo eve instanceof Person, ritornerebbe false. Se proviamo ad accedere eve.species, ritornerebbeundefined .

In altre parole, dobbiamo collegare la delega in modo che eve instanceof Personritorni vero e che le istanze del Studentdelegato siano correttamente Student.prototypee quindi Person.prototype.

MA poiché lo chiamiamo con la newparola chiave, ricordi cosa aggiunge quell'invocazione? Si chiamerebbe Object.create(Student.prototype), ed è così che abbiamo creato quella relazione delegativa tra Studente Student.prototype. Si noti che in questo momento, Student.prototypeè vuoto. Quindi cercare .speciesun'istanza di Studentfallirebbe in quanto delega solo Student.prototype e la .speciesproprietà non esisteStudent.prototype .

Quando lo assegniamo Student.prototypea noi stessi Object.create(Person.prototype), Student.prototypepoi si delega Person.prototypee guardando in alto eve.speciestornerà humancome ci aspettiamo. Presumibilmente vorremmo che ereditasse da Student.prototype AND Person.prototype. Quindi dobbiamo risolvere tutto ciò.

/* This sets up the prototypal delegation correctly 
 *so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
 *This also allows us to add more things to Student.prototype 
 *that Person.prototype may not have
 *So now a failed lookup on an instance of Student 
 *will first look at Student.prototype, 
 *and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);

Ora la delegazione funziona, ma stiamo sovrascrivendo Student.prototypecon un di Person.prototype. Quindi, se chiamiamo Student.prototype.constructor, indicherebbe Personinvece di Student. Questo è il motivo per cui dobbiamo ripararlo.

// Now we fix what the .constructor property is pointing to    
Student.prototype.constructor = Student

// If we check instanceof here
console.log(eve instanceof Person) // true

In ES5, la nostra constructorproprietà è un riferimento che si riferisce a una funzione che abbiamo scritto con l'intento di essere un "costruttore". A parte ciò che newci fornisce la parola chiave, il costruttore è altrimenti una funzione "semplice".

In ES6, constructorora è integrato nel modo in cui scriviamo le classi - come in, viene fornito come metodo quando dichiariamo una classe. Questo è semplicemente zucchero sintattico, ma ci concede alcune comodità come l'accesso a una superquando stiamo estendendo una classe esistente. Quindi scriveremo il codice sopra in questo modo:

class Person {
  // constructor function here
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  // static getter instead of a static property
  static get species() {
    return 'human';
  }
}

class Student extends Person {
   constructor(name, age, school) {
      // calling the superclass constructor
      super(name, age);
      this.school = school;
   }
}

eve instanceof Studentrestituito true. Vedere stackoverflow.com/questions/35537995/… per una spiegazione. Anche quando dici a which is, at the moment, nothingcosa ti riferisci? Ogni funzione ha un prototipo, quindi se controllo Student.prototypeè qualcosa.
Aseem Bansal,

Errore mio. Avrebbe dovuto leggere "eve instanceof Person" che restituirebbe false. Modificherò quella parte. Hai ragione che ogni funzione ha una proprietà prototipo. Tuttavia , senza assegnare il prototipo a Object.create(Person.prototype), Student.prototypeè vuoto. Quindi, se effettuiamo il log eve.species, non verrà delegato correttamente alla sua superclasse, Person, e non effettuerà il log 'human'. Presumibilmente, vogliamo che ogni sottoclasse erediti dal suo prototipo e anche dal suo prototipo di super.
bthehuman

Per chiarire, which is, at the moment, nothingintendevo che l' Student.prototypeoggetto è vuoto.
bthehuman

Altro sul prototipo: senza l'assegnazione di Student.prototypea Object.create(Person.prototype)- che è, se ricordi, allo stesso modo in cui tutte le istanze di Persona sono impostate per delegare a Person.prototype- cercare una proprietà su un'istanza di Studentdelegare solo Student.prototype . Quindi eve.speciesfallirà la sua ricerca. Se lo assegniamo, esso Student.prototypestesso si delega Person.prototypee eve.speciestornerà a guardare in alto human.
bthehuman,

Sembra che ci siano alcune cose sbagliate qui: "È necessario quando si tenta di emulare 'sottoclasse' [...] in modo che quando si verifica se un'istanza è instanceil costruttore di 'sottoclasse', sarà accurata." No, instanceofnon usa constructor. "Tuttavia, se cerchiamo il .prototype.constructor dello studente, indicherebbe comunque Person" No, lo sarà Student. Non capisco il punto di questo esempio. Chiamare una funzione in un costruttore non è ereditarietà. "In ES6, il costruttore è ora una funzione effettiva anziché un riferimento a una funzione" Uh cosa?
Felix Kling,

10

Non sarei d'accordo. Non è necessario impostare il prototipo. Prendi esattamente lo stesso codice ma rimuovi la linea prototype.constructor. Cambia qualcosa? No. Ora, apporta le seguenti modifiche:

Person = function () {
    this.favoriteColor = 'black';
}

Student = function () {
    Person.call(this);
    this.favoriteColor = 'blue';
}

e alla fine del codice di prova ...

alert(student1.favoriteColor);

Il colore sarà blu.

Una modifica al prototype.constructor, nella mia esperienza, non fa molto a meno che tu non stia facendo cose molto specifiche e molto complicate che probabilmente non sono comunque buone pratiche :)

Modifica: Dopo aver frugato un po 'in giro per il web e aver fatto qualche sperimentazione, sembra che le persone impostino il costruttore in modo che "assomigli" alla cosa che viene costruita con "nuovo". Immagino che direi che il problema con questo è che javascript è un linguaggio prototipo - non esiste eredità. Ma la maggior parte dei programmatori proviene da un background di programmazione che spinge l'eredità come "la strada". Quindi escogitiamo ogni sorta di cose per cercare di rendere questo linguaggio prototipo un linguaggio "classico", come l'estensione di "classi". In realtà, nell'esempio che hanno dato, un nuovo studente è una persona - non si sta "estendendo" da un altro studente .. lo studente è tutto sulla persona, e qualunque cosa sia la persona è anche lo studente. Estendi lo studente e qualunque cosa tu '

Crockford è un po 'pazzo e troppo zelante, ma fai delle letture serie su alcune delle cose che ha scritto ... ti farà guardare queste cose in modo molto diverso.


8
Ciò non eredita la catena di prototipi.
Cypher,

1
@Cypher applauso lento benvenuto nella conversazione, quattro anni dopo. Sì, la catena di prototipi viene ereditata, indipendentemente dal fatto che si sovrascriva prototype.constructor. Prova a provarlo.
Stephen,

7
Ti manca il codice che eredita il prototipo. Benvenuti in Internet.
Cypher,

1
Lo snippet di codice @Cypher si basava sul codice nell'articolo collegato. Benvenuti a leggere la domanda nella sua interezza. Oh. Aspettare.
Stephen,

1
@macher lo intendevo come eredità classica. Scarsa scelta delle parole da parte mia.
Stephen,

9

Questo ha l'enorme trappola che se hai scritto

Student.prototype.constructor = Student;

ma poi se c'era un insegnante il cui prototipo era anche Person e tu scrivevi

Teacher.prototype.constructor = Teacher;

allora il costruttore Studente è ora Insegnante!

Modifica: puoi evitarlo assicurandoti di aver impostato i prototipi di Studente e Insegnante usando nuove istanze della classe Person create usando Object.create, come nell'esempio di Mozilla.

Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);

1
Student.prototype = Object.create(...)è assunto in questa domanda. Questa risposta non aggiunge altro che possibile confusione.
André Chalella,

3
@ AndréNeves Ho trovato utile questa risposta. Object.create(...)viene utilizzato nell'articolo MDN che ha generato la domanda, ma non nella domanda stessa. Sono sicuro che molte persone non fanno clic.
Alex Ross,

L'articolo collegato a cui fa riferimento la domanda alreay utilizza Object.create (). Questa risposta e l'Edit o la risposta non sono davvero rilevanti, ed è a dir poco confuso :-)
Drenai,

1
Il punto più ampio è che ci sono gotcha che cattureranno le persone nuove ai prototipi Javascript. Se stiamo discutendo nel 2016, allora dovresti davvero usare le classi ES6, Babel e / o Typescript. Ma se vuoi davvero costruire manualmente le classi in questo modo, aiuta a capire come funzionano realmente le catene di prototipi per sfruttare il loro potere. Puoi usare qualsiasi oggetto come prototipo e forse non vuoi nuovo un oggetto separato. Inoltre, prima che HTML 5 fosse completamente diffuso, Object.create non era sempre disponibile, quindi era più facile impostare una classe in modo errato.
James D,

5

Finora la confusione è ancora lì.

Seguendo l'esempio originale, poiché si dispone di un oggetto esistente student1come:

var student1 = new Student("Janet", "Applied Physics");

Supponiamo che tu non voglia sapere come student1viene creato, vuoi solo un altro oggetto simile, puoi usare la proprietà del costruttore student1come:

var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");

Qui non riuscirà a ottenere le proprietà Studentse la proprietà del costruttore non è impostata. Piuttosto creerà un Personoggetto.


2

Ho un buon esempio di codice del perché è davvero necessario impostare il costruttore del prototipo.

function CarFactory(name){ 
   this.name=name;  
} 
CarFactory.prototype.CreateNewCar = function(){ 
    return new this.constructor("New Car "+ this.name); 
} 
CarFactory.prototype.toString=function(){ 
    return 'Car Factory ' + this.name;
} 

AudiFactory.prototype = new CarFactory();      // Here's where the inheritance occurs 
AudiFactory.prototype.constructor=AudiFactory;       // Otherwise instances of Audi would have a constructor of Car 

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

AudiFactory.prototype.toString=function(){ 
    return 'Audi Factory ' + this.name;
} 

var myAudiFactory = new AudiFactory('');
  alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');            

var newCar =  myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory 
alert(newCar); 

/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class )..   Dont we want our new car from Audi factory ???? 
*/

Il tuo createNewCarmetodo è creare fabbriche !? Anche questo sembra che avrebbe dovuto essere usato var audiFactory = new CarFactory("Audi")piuttosto che usare l'ereditarietà.
Bergi,

Il tuo esempio sta usando this.constructorinternamente, quindi non sorprende che debba essere impostato. Hai qualche esempio senza di essa?
Dmitri Zaitsev,

1

Non c'è bisogno di 'classi' di funzioni zuccherate o di usare 'Nuovo' in questi giorni. Usa letterali di oggetti.

Il prototipo di oggetto è già una "classe". Quando si definisce un oggetto letterale, è già un'istanza dell'oggetto prototipo. Questi possono anche fungere da prototipo di un altro oggetto, ecc.

const Person = {
  name: '[Person.name]',
  greeting: function() {
    console.log( `My name is ${ this.name || '[Name not assigned]' }` );
  }
};
// Person.greeting = function() {...} // or define outside the obj if you must

// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John 
// Define new greeting method
john.greeting = function() {
    console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John

// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane 

// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]

Vale la pena leggere :

I linguaggi orientati agli oggetti basati su classi, come Java e C ++, sono basati sul concetto di due entità distinte: classi ed istanze.

...

Un linguaggio basato sui prototipi, come JavaScript, non fa questa distinzione: ha semplicemente degli oggetti. Un linguaggio basato su prototipo ha la nozione di oggetto prototipico, un oggetto usato come modello da cui ottenere le proprietà iniziali per un nuovo oggetto. Qualsiasi oggetto può specificare le proprie proprietà, sia quando lo si crea che in fase di esecuzione. Inoltre, qualsiasi oggetto può essere associato come prototipo per un altro oggetto, consentendo al secondo oggetto di condividere le proprietà del primo oggetto


1

È necessario quando è necessaria un'alternativa toStringsenza il monkeypatching:

//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();

//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);

//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();

//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();

//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();

//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function() 
  {
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
  
  while (i < max) 
    {
    Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);

    i = i + 1;
    }    
  }

Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);


Cosa dovrebbe fare qualcosa di tutto ciò? foo.constructor()??
Ry-

0

EDIT, in realtà mi sbagliavo. Commentare la linea non cambia affatto il suo comportamento. (L'ho provato)


Sì, è necessario Quando lo fai

Student.prototype = new Person();  

Student.prototype.constructordiventa Person. Pertanto, la chiamata Student()restituirebbe un oggetto creato da Person. Se poi lo fai

Student.prototype.constructor = Student; 

Student.prototype.constructorviene ripristinato su Student. Ora quando lo chiami Student()viene eseguito Student, che chiama il costruttore principale Parent(), restituisce l'oggetto correttamente ereditato. Se non lo avessi ripristinato Student.prototype.constructorprima di chiamarlo, otterrai un oggetto che non avrebbe nessuna delle proprietà impostate Student().


3
La struttura del prototipo può diventare una persona, ma è appropriato in quanto eredita tutte le proprietà e tutti i metodi dalla Persona. La creazione di un nuovo Studente () senza impostare prototype.constructor chiama in modo appropriato il proprio costruttore.
Stephen,

0

Data la semplice funzione di costruzione:

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


console.log(Person.prototype.constructor) // function Person(){...}

Person.prototype = { //constructor in this case is Object
    sayName: function(){
        return this.name;
    }
}

var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}

Per impostazione predefinita (dalla specifica https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor ), tutti i prototipi ottengono automaticamente una proprietà denominata costruttore che punta alla funzione su che è una proprietà. A seconda del costruttore, al prototipo potrebbero essere aggiunte altre proprietà e metodi, che non è una pratica molto comune ma è comunque consentito per le estensioni.

Quindi semplicemente rispondendo: dobbiamo assicurarci che il valore in prototype.constructor sia impostato correttamente come si suppone dalla specifica.

Dobbiamo sempre impostare correttamente questo valore? Aiuta con il debug e rende la struttura interna coerente con le specifiche. Dovremmo sicuramente quando la nostra API viene utilizzata dalle terze parti, ma non quando il codice viene finalmente eseguito in fase di esecuzione.


0

Ecco un esempio di MDN che ho trovato molto utile per comprenderne gli usi.

In JavaScript, abbiamo async functionsquale restituisce l' oggetto AsyncFunction . AsyncFunctionnon è un oggetto globale ma è possibile recuperarlo utilizzando la constructorproprietà e utilizzandolo.

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor

var a = new AsyncFunction('a', 
                          'b', 
                          'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');

a(10, 20).then(v => {
  console.log(v); // prints 30 after 4 seconds
});

-1

Non è necessario. È solo una delle tante cose tradizionali, i campioni di OOP fanno per provare a trasformare l'eredità prototipica di JavaScript in eredità classica. L'unica cosa che segue

Student.prototype.constructor = Student; 

sì, è che ora hai un riferimento all'attuale "costruttore".

Nella risposta di Wayne, che è stata contrassegnata come corretta, potresti fare esattamente la stessa cosa che fa il seguente codice

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

con il codice qui sotto (basta sostituire questo.costruttore con Persona)

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new Person(this.name);
}; 

Grazie a Dio che con ES6 i puristi dell'eredità classica possono usare gli operatori nativi del linguaggio come classe, estensione e super e non dobbiamo vedere come correzioni di prototype.constructor e riferimenti parent.

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.