Ao fazer herança, porque não simplesmente modificar a propriedade [[Prototype]] da classe derivada

5

Eu tenho lido muito ultimamente sobre alguns dos principais conceitos de JS e a herança é um pouco confusa.

Aqui estão os métodos que eu conheço:

// 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. Usando uma função temporária

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

2. Usando uma Parent instance

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

3. Usando Object#create

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Depois de examinar as cadeias de protótipos para todos os métodos, percebi que todos produzem o mesmo resultado (o que é óbvio). Mas em todos esses métodos, há uma coisa que é comum. Estamos criando um terceiro objeto para substituir o protótipo e, em seguida, redefinir o construtor. são dois overrides envolvidos: -

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

Isso me fez pensar: Por que não simplesmente Child.prototype.__proto__ = Parent.prototype ? Ou uma alternativa mais segura , Object.setPrototypeOf(Child.prototype, Parent.prototype) .

Qual é o dano nisso?

    
por zhirzh 09.03.2017 / 07:52
fonte

1 resposta

3

A Mozilla resume por que modificar __proto__ é uma má ideia:

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

O método Object.setPrototypeOf vem com um aviso semelhante sobre desempenho:

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().

Problemas de desempenho à parte, eles continuam alertando que __proto__ é um recurso legado:

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

Além disso, muitos navegadores permitiram que você definisse a propriedade __proto__ , o que permite ao homem atacar no meio dentro de sua hierarquia de classes (não que essa seja a única maneira de fazer isso em JavaScript).

O motivo para usar Object.create é simples:

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

Fonte: link

O método Object.create foi explicitamente criado para fornecer um mecanismo para configurar a herança prototypal e, opcionalmente, incluir definições para propriedades adicionais para evitar as outras duas soluções alternativas / hacks que você propôs:

  • Usando uma função construtora temporária apontando para o protótipo da classe pai

  • Criando uma instância descartável da classe pai, que não é inicializada corretamente, como um meio de configurar a cadeia de protótipos.

por 09.03.2017 / 15:03
fonte