Los dos ejemplos de código que demostró en su pregunta hacen uso de herencia prototípica. De hecho, cualquier código orientado a objetos que escriba en JavaScript es un paradigma de herencia prototípica. JavaScript simplemente no tiene herencia clásica. Esto debería aclarar un poco las cosas:
Inheritance
|
+-----------------------------+
| |
v v
Prototypal Classical
|
+------------------------------+
| |
v v
Prototypal Pattern Constructor Pattern
Como puede ver, la herencia prototípica y la herencia clásica son dos paradigmas diferentes de herencia. Algunos lenguajes como Self, Lua y JavaScript admiten la herencia de prototipos. Sin embargo, la mayoría de lenguajes como C ++, Java y C # admiten la herencia clásica.
Una descripción general rápida de la programación orientada a objetos
Tanto la herencia prototípica como la herencia clásica son paradigmas de programación orientados a objetos (es decir, tratan con objetos). Los objetos son simplemente abstracciones que encapsulan las propiedades de una entidad del mundo real (es decir, representan palabras reales en el programa). Esto se conoce como abstracción.
Abstracción: la representación de cosas del mundo real en programas de computadora.
En teoría, una abstracción se define como "un concepto general formado al extraer características comunes de ejemplos específicos". Sin embargo, por el bien de esta explicación, usaremos la definición antes mencionada.
Ahora bien, algunos objetos tienen muchas cosas en común. Por ejemplo, una moto de barro y una Harley Davidson tienen mucho en común.
Una bici de barro:
Una Harley Davidson:
Una moto de barro y una Harley Davidson son ambas motos. Por lo tanto, una bicicleta es una generalización tanto de una bicicleta de barro como de una Harley Davidson.
Bike
|
+---------------------------------+
| |
v v
Mud Bike Harley Davidson
En el ejemplo anterior, la moto, la moto de barro y la Harley Davidson son todas abstracciones. Sin embargo, la moto es una abstracción más general de la moto de barro y la Harley Davidson (es decir, tanto la moto de barro como la Harley Davidson son tipos específicos de motos).
Generalización: una abstracción de una abstracción más específica.
En la programación orientada a objetos creamos objetos (que son abstracciones de entidades del mundo real) y usamos clases o prototipos para crear generalizaciones de estos objetos. Las generalizaciones se crean por herencia. Una bicicleta es una generalización de una bicicleta de barro. De ahí que las motos de barro hereden de las bicicletas.
Programación clásica orientada a objetos
En la programación clásica orientada a objetos tenemos dos tipos de abstracciones: clases y objetos. Un objeto, como se mencionó anteriormente, es una abstracción de una entidad del mundo real. Por otro lado, una clase es una abstracción de un objeto u otra clase (es decir, es una generalización). Por ejemplo, considere:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | Man | Class of object johnDoe. |
| 3 | Human | Superclass of class Man. |
+----------------------+----------------+---------------------------------------+
Como puede ver en los lenguajes de programación orientados a objetos clásicos, los objetos son solo abstracciones (es decir, todos los objetos tienen un nivel de abstracción de 1) y las clases son solo generalizaciones (es decir, todas las clases tienen un nivel de abstracción mayor que 1).
Los objetos en los lenguajes de programación orientados a objetos clásicos solo se pueden crear instanciando clases:
class Human {
// ...
}
class Man extends Human {
// ...
}
Man johnDoe = new Man();
En resumen, en los lenguajes de programación orientados a objetos clásicos, los objetos son abstracciones de entidades del mundo real y las clases son generalizaciones (es decir, abstracciones de objetos u otras clases).
Por lo tanto, a medida que aumenta el nivel de abstracción, las entidades se vuelven más generales y a medida que el nivel de abstracción disminuye, las entidades se vuelven más específicas. En este sentido, el nivel de abstracción es análogo a una escala que va desde entidades más específicas hasta entidades más generales.
Programación prototípica orientada a objetos
Los lenguajes de programación orientados a objetos prototípicos son mucho más simples que los lenguajes de programación orientados a objetos clásicos porque en la programación orientada a objetos prototípicos solo tenemos un tipo de abstracción (es decir, objetos). Por ejemplo, considere:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | man | Prototype of object johnDoe. |
| 3 | human | Prototype of object man. |
+----------------------+----------------+---------------------------------------+
Como puede ver en los lenguajes de programación prototípicos orientados a objetos, los objetos son abstracciones de entidades del mundo real (en cuyo caso simplemente se denominan objetos) u otros objetos (en cuyo caso se denominan prototipos de los objetos que abstraen). Por tanto, un prototipo es una generalización.
Los objetos en lenguajes de programación orientados a objetos prototípicos pueden crearse ex-nihilo (es decir, de la nada) o de otro objeto (que se convierte en el prototipo del objeto recién creado):
var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);
En mi humilde opinión, los lenguajes de programación orientados a objetos prototípicos son más poderosos que los lenguajes de programación orientados a objetos clásicos porque:
- Solo hay un tipo de abstracción.
- Las generalizaciones son simplemente objetos.
A estas alturas, debe haberse dado cuenta de la diferencia entre la herencia clásica y la herencia prototípica. La herencia clásica se limita a las clases que heredan de otras clases. Sin embargo, la herencia de prototipos incluye no solo los prototipos que heredan de otros prototipos, sino también los objetos que heredan de los prototipos.
Isomorfismo de clase prototipo
Debes haber notado que los prototipos y las clases son muy similares. Es verdad. Son. De hecho, son tan similares que puedes usar prototipos para modelar clases:
function CLASS(base, body) {
if (arguments.length < 2) body = base, base = Object.prototype;
var prototype = Object.create(base, {new: {value: create}});
return body.call(prototype, base), prototype;
function create() {
var self = Object.create(prototype);
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
}
}
Con la CLASS
función anterior , puede crear prototipos que parecen clases:
var Human = CLASS(function () {
var milliseconds = 1
, seconds = 1000 * milliseconds
, minutes = 60 * seconds
, hours = 60 * minutes
, days = 24 * hours
, years = 365.2425 * days;
this.constructor = function (name, sex, dob) {
this.name = name;
this.sex = sex;
this.dob = dob;
};
this.age = function () {
return Math.floor((new Date - this.dob) / years);
};
});
var Man = CLASS(Human, function (Human) {
this.constructor = function (name, dob) {
Human.constructor.call(this, name, "male", dob);
if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
};
});
var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));
Sin embargo, lo contrario no es cierto (es decir, no puede usar clases para modelar prototipos). Esto se debe a que los prototipos son objetos, pero las clases no son objetos. Son un tipo de abstracción completamente diferente.
Conclusión
En resumen, aprendimos que una abstracción es un "concepto general formado al extraer características comunes de ejemplos específicos" y que la generalización es "una abstracción de una abstracción más específica" . También aprendimos sobre las diferencias entre la herencia prototípica y clásica y cómo ambas son dos caras de la misma moneda.
Como nota de despedida, me gustaría comentar que hay dos patrones de herencia prototípica: el patrón prototípico y el patrón constructor. El patrón prototípico es el patrón canónico de herencia prototípica, mientras que el patrón constructor se usa para hacer que la herencia prototípica se parezca más a la herencia clásica. Personalmente prefiero el patrón prototípico.
PD: Soy el tipo que escribió la publicación del blog " Por qué importa la herencia prototípica " y respondió a la pregunta "¿ Beneficios de la herencia prototípica sobre la clásica? ". Mi respuesta es la respuesta aceptada.