Quando si esegue l'ereditarietà, perché non modificare semplicemente la proprietà [[Prototype]] della classe derivata

5

Ultimamente ho letto molto su alcuni concetti chiave di JS e l'ereditarietà è un po 'confusa.

Ecco i metodi che conosco:

// Base class
function Parent(foo) {
  if (foo === undefined) {
    throw new TypeError('foo is undefined');
  }

  this.foo = foo;
}

// Derived class
function Child(foo, bar) {
  if (foo === undefined) {
    throw new TypeError('foo is undefined');
  }

  if (bar === undefined) {
    throw new TypeError('bar is undefined');
  }

  Parent.call(this, foo);
  this.bar = bar;
}

1. Utilizzo di una funzione temporanea

function tmpFn(){}
tmpFn.prototype = Parent.prototype;
Child.prototype = new tmpFn();
Child.prototype.constructor = Child;

2. Utilizzo di un'istanza Parent

Child.prototype = new Parent();       // fail
Child.prototype = new Parent(null);   // hax
Child.prototype.constructor = Child;

3. Utilizzando Object#create

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

Dopo aver esaminato le catene di prototipi per tutti i metodi, mi sono reso conto che tutti producono lo stesso risultato (che è abbastanza ovvio). Ma in tutti questi metodi, c'è una cosa che è comune. Stiamo creando un terzo oggetto per sostituire il prototipo e quindi reimpostare il costruttore. ci sono due override coinvolti: -

  1. Child.prototype = ...
  2. Child.prototype.constructor = Child

Questo mi ha fatto pensare: perché non fare semplicemente Child.prototype.__proto__ = Parent.prototype ? O un'alternativa più sicura , Object.setPrototypeOf(Child.prototype, Parent.prototype) .

Qual è il danno in questo?

    
posta zhirzh 09.03.2017 - 07:52
fonte

1 risposta

3

Mozilla riassume perché la modifica di __proto__ è una cattiva idea:

Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in obj.__proto__ = ... statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().

Fonte: link

Il metodo Object.setPrototypeOf ha un avvertimento simile sulle prestazioni:

Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine. The effects on performance of altering inheritance are subtle and far-flung, and are not limited to simply the time spent in obj.proto = ... statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered. If you care about performance you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().

A parte i problemi di rendimento, continuano a segnalare che __proto__ è una funzione legacy:

Warning: While Object.prototype.proto is supported today in most browsers, its existence and exact behavior has only been standardized in the ECMAScript 2015 specification as a legacy feature to ensure compatibility for web browsers.

Fonte: fonte: link

Inoltre, molti browser ti hanno permesso di impostare la proprietà __proto__ , che consente gli attacchi man in the middle all'interno della tua gerarchia di classi (non che questo sia l'unico modo per farlo in JavaScript).

Il motivo per usare Object.create è semplice:

The Object.create() method creates a new object with the specified prototype object and properties.

Fonte: link

Il metodo Object.create è stato creato in modo esplicito per fornire un meccanismo per l'impostazione dell'ereditarietà prototipale e facoltativamente includendo le definizioni per le proprietà aggiuntive per evitare le altre due soluzioni alternative / hack proposte:

  • Uso di una funzione di costruzione temporanea che punta al prototipo della classe genitrice

  • Creazione di un'istanza throwaway della classe genitore, che non è inizializzata correttamente, come mezzo per impostare la catena del prototipo.

risposta data 09.03.2017 - 15:03
fonte

Leggi altre domande sui tag