tutorial herencia es6 ejemplos javascript prototype lua

javascript - es6 - ¿Un ejemplo de herencia prototípica que no implica la simulación de la herencia clásica?



prototype javascript ejemplos (4)

He leído los siguientes QAs y todos ellos examinan el uso de la herencia prototípica para simular la herencia clásica.

Buen ejemplo de la herencia basada en prototipos de JavaScript

herencia de JavaScript

Usar patrones de herencia en JavaScript

¿No hay un ejemplo funcional de herencia prototípica en la naturaleza? ¿Simulando formas de vida, tal vez? ¿Qué problemas, aparte de los creados o no resueltos adecuadamente por el lenguaje de programación, se beneficiarían de la herencia prototípica en bruto?



La herencia es herencia, por lo que puede obtener la misma funcionalidad básica de cualquiera de los dos.

Un beneficio de la herencia prototípica en JavaScript es permitir la adición dinámica de nuevos métodos en tiempo de ejecución o la alteración de los antiguos disponibles para todos los objetos (sin agregar una penalización de memoria por objeto).

Esto puede ser peligroso, especialmente cuando los métodos incorporados, como String u Object, tienen sus métodos incorporados anulados de forma retrógrada (o amenazante).

String.prototype.replace = function () { return ''hahaha''; };

Pero puede ser de gran alcance cuando las implementaciones de algunos navegadores o bibliotecas son inadecuadas en cuanto a funcionalidad o tienen un rendimiento inferior.

También ayuda a la modularidad, extensibilidad y mejora de las bibliotecas. Si incluye la biblioteca de alguien y descubre que su implementación para un método en particular podría optimizarse mejor, puede ingresar su código sin alterarlo, al mismo tiempo que puede mejorarlo o agregarle funciones y beneficiar a todos los objetos definidos fuera de su alcance. biblioteca (al menos tan pronto como empiece a agregarlo al prototipo). Una biblioteca podría incluso intercambiar implementaciones según las preferencias del usuario (probablemente no sea una buena idea, aunque puede interferir con otros códigos que usen ese método) o dejar que definan dinámicamente los nombres de los métodos que desean usar.

Y el comportamiento prototípico incluso entra en juego incluso dentro de una "clase", ya que puede aprovechar la conveniencia de almacenar directamente en el objeto (aunque se agrega a la memoria en esos casos y probablemente sea mejor crear una nueva clase, pero todavía puede ser conveniente).

function Dog (type) { if (type === ''poodle'') { this.bark = function () { alert(''(yapyapyap)''); }; } } Dog.prototype.bark = function () { alert(''(woof)''); }; var muffy = new Dog(''poodle''); muffy.bark(); // ''(yapyapyap)'' var rover = new Dog(); rover.bark(); // ''(woof)''

El hecho de que el prototipo sea algo que puede cambiarse o intercambiarse dinámicamente en el enfoque prototípico de JavaScript también le permite crear dinámicamente nuevas clases en tiempo de ejecución a diferencia de algunos lenguajes más tradicionales, al menos ofreciendo algo más de brevedad expresiva:

function Creature () {} Creature.prototype.respire = function () { return ''oooooh''; }; function createClass (o, f) { f = f || function f () {} f.prototype = (typeof o === ''function'') ? o.prototype : o.constructor.prototype; f.prototype.constructor = f; return f; } var animals = [''Dog'', ''Tiger'', ''Lion'', ''Frog'', ''Kangaroo'']; animals.forEach(function (animal) { window[animal] = createClass(Creature); }); var rover = new Dog();

Finalmente, puede evitar las jerarquías estrictas, tomando prestado solo lo que necesita y aprovechando las características heredables:

function createMixinClass (old, constructor, newMethods) { if (typeof constructor === ''object'') { newMethods = constructor; constructor = null; } var proto = old.prototype, constructor = constructor || function () {}; for (var m in proto) { constructor.prototype[m] = proto[m]; } for (var method in newMethods) { if (!newMethods[method]) { delete constructor.prototype[method]; } else { constructor.prototype[method] = newMethods[method]; } } return constructor; } var Cat = createMixinClass(Dog, {bark:null, meow: function () {alert(''meow'');}}); var kitty = new Cat();

En resumen, no creo que haya algo tan diferente que le permita manejar nuevos tipos de problemas, pero ofrece más flexibilidad, especialmente con algunas utilidades reutilizables que son útiles.


No es un ejemplo de "enseñanza", pero el uso del "mundo real" de la herencia de prototipos es jQuery. $.fn es en realidad el prototipo de la colección jQuery mágica, y los complementos jQuery le agregan métodos para agregar funcionalidad a cualquier colección de jQuery.


Hay muchos ejemplos de herencia prototípica en la naturaleza. En particular, jQuery lo usa. Cada vez que selecciones jQuery, estás utilizando un prototipo de delegado para heredar los métodos de jQuery. También es de uso común en una variedad de aplicaciones web, incluida la plataforma Creative Cloud de Abode, muchos productos de Yahoo, etc.

De hecho, cada implementación de herencia clásica en JavaScript está empleando la herencia prototípica para imitar la herencia clásica, necesaria solo como una conveniencia para los programadores que están más familiarizados con la herencia clásica que con la herencia prototípica. La herencia prototípica es tan flexible que es trivial imitar las características de la herencia clásica usando la herencia prototípica. Lo opuesto no es verdad.

La herencia prototípica significa simplemente que un objeto hereda directamente de otro objeto. Aquí hay un ejemplo:

var switchProto = { isOn: function isOn() { return this.state; }, toggle: function toggle() { this.state = !this.state; return this; }, state: false }, switch1 = Object.create(switchProto), switch2 = Object.create(switchProto);

Es común poner esa llamada Object.create() en una función de fábrica para hacer que la instanciación de objetos sea más conveniente.

Hay muchos problemas con la herencia clásica que no existen con la herencia prototípica, como por ejemplo:

Herencia clásica

Acoplamiento apretado La herencia es el acoplamiento más ajustado disponible en el diseño OO. Las clases descendientes tienen un conocimiento profundo de sus clases ancestrales.

Jerarquías inflexibles (también conocidas como duplicación por necesidad) . Las jerarquías monoparentales rara vez son capaces de describir todos los casos de uso posibles. Eventualmente, todas las jerarquías están "equivocadas" para nuevos usos, un problema que requiere duplicación de código.

La herencia múltiple es complicada A menudo es conveniente heredar de más de un padre. Ese proceso es excesivamente complejo y su implementación es inconsistente con el proceso de herencia individual, lo que hace que sea más difícil de leer y entender.

Arquitectura frágil . Debido al acoplamiento ajustado, a menudo es difícil refactorizar una clase con el diseño "incorrecto", porque mucha de la funcionalidad existente depende del diseño existente.

El problema Gorila / Banana . A menudo, hay partes del padre que no desea heredar. La creación de subclase le permite anular las propiedades del elemento principal, pero no le permite seleccionar qué propiedades desea heredar.

Herencia prototípica

Para comprender cómo la herencia prototípica resuelve estos problemas, primero debe comprender que existen dos tipos diferentes de herencia prototípica. JavaScript es compatible con ambos:

Delegación . Si una propiedad no se encuentra en una instancia, se busca en el prototipo de la instancia. Esto le permite compartir métodos entre muchas instancias, proporcionándole el patrón flyweight de forma gratuita .

Concatenación . La capacidad de agregar propiedades dinámicamente a un objeto le permite copiar libremente cualquier propiedad de un objeto a otro, en conjunto o selectivamente.

Puede combinar ambas formas de herencia prototípica para lograr un sistema muy flexible de reutilización de código. Tan flexible de hecho, que es trivial implementar herencia clásica con prototipos. Lo opuesto no es verdad.

La herencia prototípica permite la mayoría de las funciones importantes que encontrará en los idiomas clásicos. En JavaScript, los cierres y las funciones de fábrica le permiten implementar un estado privado, y la herencia funcional se puede combinar fácilmente con prototipos para agregar mixins que también admitan la privacidad de los datos.

Algunas ventajas de la herencia prototípica:

Acoplamiento flojo . Una instancia nunca tiene la necesidad de hacer una referencia directa a una clase o prototipo principal. Es posible almacenar una referencia al prototipo de un objeto, pero no es aconsejable, ya que promovería un acoplamiento estricto en la jerarquía de objetos, uno de los mayores peligros de la herencia clásica.

Jerarquías planas Es trivial con OO prototípico mantener las jerarquías de herencia planas: mediante concatenación y delegación, puede tener un solo nivel de delegación de objetos y una única instancia, sin referencias a clases principales.

Herencia múltiple trivial . Heredar de antepasados ​​múltiples es tan fácil como combinar propiedades de múltiples prototipos usando concatenación para formar un nuevo objeto o un nuevo delegado para un nuevo objeto.

Arquitectura flexible Como puede heredar de forma selectiva con Prototypal OO, no tiene que preocuparse por el problema del "diseño incorrecto". Una nueva clase puede heredar cualquier combinación de propiedades de cualquier combinación de objetos fuente. Debido a la facilidad de aplanar la jerarquía, un cambio en un lugar no necesariamente causa ondas en una larga cadena de objetos descendientes.

No más gorilas . La herencia selectiva elimina el problema del gorila banana.

No conozco ninguna ventaja que la herencia clásica tenga sobre la herencia prototípica. Si alguien conoce alguno, por favor ilumíname.