Recientemente leí sobre el uso de llamadas de JavaScript en MDC
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
un enlace del ejemplo que se muestra a continuación, todavía no lo entiendo.
¿Por qué están usando la herencia aquí de esta manera?
Prod_dept.prototype = new Product();
¿Es esto necesario? Porque hay una llamada al superconstructor en
Prod_dept()
de todos modos, así
Product.call
¿Es esto simplemente un comportamiento común? ¿Cuándo es mejor usar call para el superconstructor o usar la cadena de prototipos?
function Product(name, value){
this.name = name;
if(value >= 1000)
this.value = 999;
else
this.value = value;
}
function Prod_dept(name, value, dept){
this.dept = dept;
Product.call(this, name, value);
}
Prod_dept.prototype = new Product();
// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");
Gracias por aclarar las cosas
javascript
inheritance
call
chaining
prototype-programming
Jeremy S.
fuente
fuente
Respuestas:
La respuesta a la pregunta real es que debes hacer ambas cosas:
Por lo tanto, no debe llamar al constructor del padre al configurar la herencia. Solo al crear una instancia de un objeto que hereda de otro.
La respuesta de Chris Morgan está casi completa, falta un pequeño detalle (propiedad del constructor). Permítanme sugerir un método para configurar la herencia.
function extend(base, sub) { // Avoid instantiating the base class just to setup inheritance // Also, do a recursive merge of two prototypes, so we don't overwrite // the existing prototype, but still maintain the inheritance chain // Thanks to @ccnokes var origProto = sub.prototype; sub.prototype = Object.create(base.prototype); for (var key in origProto) { sub.prototype[key] = origProto[key]; } // The constructor property was set wrong, let's fix it Object.defineProperty(sub.prototype, 'constructor', { enumerable: false, value: sub }); } // Let's try this function Animal(name) { this.name = name; } Animal.prototype = { sayMyName: function() { console.log(this.getWordsToSay() + " " + this.name); }, getWordsToSay: function() { // Abstract } } function Dog(name) { // Call the parent's constructor Animal.call(this, name); } Dog.prototype = { getWordsToSay: function(){ return "Ruff Ruff"; } } // Setup the prototype chain the right way extend(Animal, Dog); // Here is where the Dog (and Animal) constructors are called var dog = new Dog("Lassie"); dog.sayMyName(); // Outputs Ruff Ruff Lassie console.log(dog instanceof Animal); // true console.log(dog.constructor); // Dog
Vea la publicación de mi blog para obtener aún más azúcar sintáctico al crear clases. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Técnica copiada de Ext-JS y http://www.uselesspickles.com/class_library/ y un comentario de https://stackoverflow.com/users/1397311/ccnokes
fuente
Object.defineProperty(sub.protoype, 'constructor', { enumerable: false, value: sub });
forma obtendrá exactamente el mismo "comportamiento" que cuando javascript crea una nueva instancia de una función (el constructor se establece como enumerable = falso automáticamente)Object.create
no estaba tan bien apoyado ... actualizarlo. Tenga en cuenta que la mayoría de losObject.create
polyfills se implementan utilizando la técnica que mostré originalmente.La forma ideal de hacerlo es no hacerlo
Prod_dept.prototype = new Product();
, porque este llama alProduct
constructor. Entonces, la forma ideal es clonarlo, excepto el constructor, algo como esto:function Product(...) { ... } var tmp = function(){}; tmp.prototype = Product.prototype; function Prod_dept(...) { Product.call(this, ...); } Prod_dept.prototype = new tmp(); Prod_dept.prototype.constructor = Prod_dept;
Luego, se llama al superconstructor en el momento de la construcción, que es lo que desea, porque entonces también puede pasar los parámetros.
Si observa cosas como la Biblioteca de cierre de Google, verá que así es como lo hacen.
fuente
Prod_dept.prototype.constructor = Prod_dept;
.Prod_dept.prototype.constructor = Prod_dept;
. En primer lugar, ¿por qué es necesario y por qué señala enProd_dept
lugar deProduct
?Prod_dept.prototype
es lo que se utilizará como prototipo de la salida denew Prod_dept()
. (Por lo general, ese prototipo está disponible comoinstance.__proto__
, aunque esto es un detalle de implementación). En cuanto a por quéconstructor
, es una parte estándar del lenguaje y, por lo tanto, debe proporcionarse para mantener la coherencia; es correcto por defecto, pero debido a que estamos reemplazando el prototipo por completo, debemos asignar el valor correcto nuevamente, o algunas cosas no estarán sanas (en este caso, significaría que unaProd_dept
instancia lo habría hechothis.constructor == Product
, lo cual es malo).Si ha realizado Programación Orientada a Objetos en JavaScript, sabrá que puede crear una clase de la siguiente manera:
Person = function(id, name, age){ this.id = id; this.name = name; this.age = age; alert('A new person has been accepted'); }
Hasta ahora nuestra persona de clase solo tiene dos propiedades y le vamos a dar algunos métodos. Una forma limpia de hacer esto es usar su objeto 'prototipo'. A partir de JavaScript 1.1, el objeto prototipo se introdujo en JavaScript. Este es un objeto integrado que simplifica el proceso de agregar propiedades y métodos personalizados a todas las instancias de un objeto. Agreguemos 2 métodos a nuestra clase usando su objeto 'prototipo' de la siguiente manera:
Person.prototype = { /** wake person up */ wake_up: function() { alert('I am awake'); }, /** retrieve person's age */ get_age: function() { return this.age; } }
Ahora hemos definido nuestra clase Person. ¿Y si quisiéramos definir otra clase llamada Manager que hereda algunas propiedades de Person? No tiene sentido volver a definir todas estas propiedades cuando definamos nuestra clase Manager, podemos configurarla para que herede de la clase Person. JavaScript no tiene herencia incorporada, pero podemos usar una técnica para implementar la herencia de la siguiente manera:
Inheritance_Manager = {};
// Creamos una clase de administrador de herencia (el nombre es arbitrario)Ahora démosle a nuestra clase de herencia un método llamado extender que toma los argumentos baseClass y subClassas. Dentro del método extend, crearemos una clase interna llamada función de herencia herencia () {}. La razón por la que usamos esta clase interna es para evitar confusiones entre los prototipos baseClass y subClass. A continuación, hacemos que el prototipo de nuestra clase de herencia apunte al prototipo baseClass como con el siguiente código: heritage.prototype = baseClass. prototipo; Luego copiamos el prototipo de herencia en el prototipo de subclase de la siguiente manera: subClass.prototype = nueva herencia (); Lo siguiente es especificar el constructor para nuestra subclase de la siguiente manera: subClass.prototype.constructor = subClass; Una vez que terminamos con la creación de prototipos de subclase, podemos especificar las siguientes dos líneas de código para establecer algunos punteros de clase base.
Aquí está el código completo para nuestra función de extensión:
Inheritance_Manager.extend = function(subClass, baseClass) { function inheritance() { } inheritance.prototype = baseClass.prototype; subClass.prototype = new inheritance(); subClass.prototype.constructor = subClass; subClass.baseConstructor = baseClass; subClass.superClass = baseClass.prototype; }
Ahora que hemos implementado nuestra herencia, podemos comenzar a usarla para extender nuestras clases. En este caso, vamos a extender nuestra clase Person a una clase Manager de la siguiente manera:
Definimos la clase Manager
Manager = function(id, name, age, salary) { Person.baseConstructor.call(this, id, name, age); this.salary = salary; alert('A manager has been registered.'); }
lo hacemos heredar de la persona
Si se dio cuenta, acabamos de llamar al método extend de nuestra clase Inheritance_Manager y pasamos la subClass Manager en nuestro caso y luego la baseClass Person. Tenga en cuenta que el orden es muy importante aquí. Si los intercambia, la herencia no funcionará como pretendía. También tenga en cuenta que deberá especificar esta herencia antes de poder definir nuestra subclase. Ahora definamos nuestra subclase:
Podemos agregar más métodos como el siguiente. Nuestra clase Manager siempre tendrá los métodos y propiedades definidos en la clase Person porque hereda de ella.
Manager.prototype.lead = function(){ alert('I am a good leader'); }
Ahora para probarlo, creemos dos objetos, uno de la clase Person y otro de la clase heredada Manager:
var p = new Person(1, 'Joe Tester', 26); var pm = new Manager(1, 'Joe Tester', 26, '20.000');
No dude en obtener el código completo y más comentarios en: http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx
fuente