que - javascript pdf
Javascript cuando usar prototipos (5)
Debe usar prototipos si desea declarar un método "no estático" del objeto.
var myObject = function () {
};
myObject.prototype.getA = function (){
alert("A");
};
myObject.getB = function (){
alert("B");
};
myObject.getB(); // This works fine
myObject.getA(); // Error!
var myPrototypeCopy = new myObject();
myPrototypeCopy.getA(); // This works, too.
Me gustaría entender cuándo es apropiado usar métodos prototipo en js. ¿Deberían ser siempre utilizados? ¿O hay casos en los que no se prefiere su uso y / o incurre en una penalización de rendimiento?
Al buscar en este sitio métodos comunes para el espaciado de nombres en js, parece que la mayoría usa una implementación no basada en prototipos: simplemente usa un objeto o un objeto de función para encapsular un espacio de nombres.
Viniendo de un lenguaje basado en clases, es difícil no intentar establecer paralelismos y pensar que los prototipos son como "clases" y las implementaciones de espacios de nombres que mencioné son como métodos estáticos.
Los prototipos son una optimización .
Un buen ejemplo de su uso es la biblioteca jQuery. Cada vez que obtienes un objeto jQuery usando $(''.someClass'')
, ese objeto tiene docenas de "métodos". La biblioteca podría lograr eso devolviendo un objeto:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
// etc...
};
Pero eso significaría que cada objeto jQuery en la memoria tendría docenas de ranuras con nombre que contienen los mismos métodos, una y otra vez.
En cambio, esos métodos se definen en un prototipo y todos los objetos jQuery "heredan" ese prototipo para obtener todos esos métodos a muy bajo costo de tiempo de ejecución.
Una parte vitalmente importante de cómo JQuery lo hace bien es que esto está oculto para el programador. Se trata simplemente como una optimización, no como algo de lo que debe preocuparse cuando usa la biblioteca.
El problema con JavaScript es que las funciones de constructor desnudo requieren que la persona que llama recuerde agregarles un prefijo new
o, de lo contrario, normalmente no funcionan. No hay una buena razón para esto. jQuery lo hace bien ocultando esas tonterías detrás de una función común, $
, por lo que no tiene que importar cómo se implementan los objetos.
Para que pueda crear convenientemente un objeto con un prototipo específico, ECMAScript 5 incluye una función estándar Object.create
. Una versión muy simplificada de esto se vería así:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
Simplemente se ocupa del dolor de escribir una función constructora y luego llamarla con new
.
¿Cuándo evitarías los prototipos?
Una comparación útil es con los lenguajes OO populares, como Java y C #. Estos admiten dos tipos de herencia:
- herencia de interfaz , donde
implement
unainterface
tal que la clase proporciona su propia implementación única para cada miembro de la interfaz. - herencia de implementación , donde
extend
unaclass
que proporciona implementaciones predeterminadas de algunos métodos.
En JavaScript, la herencia prototípica es un tipo de herencia de implementación . Por lo tanto, en aquellas situaciones en las que (en C # o Java) se derivaría de una clase base para obtener un comportamiento predeterminado, al que luego se le harán pequeñas modificaciones mediante anulaciones, en JavaScript, la herencia prototípica tiene sentido.
Sin embargo, si se encuentra en una situación en la que habría utilizado interfaces en C # o Java, entonces no necesita ninguna función de idioma en particular en JavaScript. No es necesario declarar explícitamente algo que represente la interfaz, y no es necesario marcar los objetos como "implementadores" de esa interfaz:
var duck = {
quack: function() { ... }
};
duck.quack(); // we''re satisfied it''s a duck!
En otras palabras, si cada "tipo" de objeto tiene sus propias definiciones de los "métodos", entonces no tiene sentido heredar de un prototipo. Después de eso, depende de la cantidad de instancias que asigne de cada tipo. Pero en muchos diseños modulares, solo hay una instancia de un tipo determinado.
Y, de hecho, muchas personas han sugerido que la herencia de implementación es malvada . Es decir, si hay algunas operaciones comunes para un tipo, entonces quizás sea más claro si no se colocan en una base / superclase, sino que se exponen simplemente como funciones ordinarias en algún módulo, al cual se pasa el objeto (s) quieres que operen
Ponga funciones en un objeto prototipo cuando va a crear muchas copias de un tipo particular de objeto y todas deben compartir comportamientos comunes. Al hacerlo, ahorrará algo de memoria al tener solo una copia de cada función, pero eso es solo el beneficio más simple.
El cambio de métodos en objetos prototipo o la adición de métodos cambia instantáneamente la naturaleza de todas las instancias de los tipos correspondientes.
Ahora, exactamente por qué haría todas estas cosas es principalmente una función del diseño de su propia aplicación, y el tipo de cosas que necesita hacer en el código del lado del cliente. (Una historia completamente diferente sería el código dentro de un servidor, mucho más fácil de imaginar haciendo más código "OO" a gran escala allí).
Si explico el término basado en la clase, entonces la persona es clase, caminar () es el método de prototipo. Entonces walk () tendrá su existencia solo después de crear un nuevo objeto con esto.
Por lo tanto, si desea crear copias de objetos como Persona, puede crear muchos usuarios. El prototipo es una buena solución ya que guarda la memoria al compartir / heredar la misma copia de la función para cada uno de los objetos en la memoria.
Mientras que la estática no es de gran ayuda en tal escenario.
function Person(){
this.name = "anonymous";
}
// its instance method and can access objects data data
Person.prototype.walk = function(){
alert("person has started walking.");
}
// its like static method
Person.ProcessPerson = function(Person p){
alert("Persons name is = " + p.name);
}
var userOne = new Person();
var userTwo = new Person();
//Call instance methods
userOne.walk();
//Call static methods
Person.ProcessPerson(userTwo);
Entonces con esto es más como un método de instancia. El enfoque del objeto es como los métodos estáticos.
https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript
Una razón para utilizar el prototype
incorporado es si va a duplicar un objeto varias veces para compartir la funcionalidad común. Al adjuntar métodos al prototipo, puede guardar los métodos de duplicación que se crean por cada instancia new
. Pero cuando adjuntas un método al prototype
, todas las instancias tendrán acceso a esos métodos.
Supongamos que tiene una clase / objeto base Car()
.
function Car() {
// do some car stuff
}
luego creas varias instancias de Car()
.
var volvo = new Car(),
saab = new Car();
Ahora, usted sabe que cada automóvil necesitará conducir, encenderse, etc. En lugar de conectar un método directamente a la clase Car()
(que ocupa la memoria por cada instancia creada), puede conectar los métodos al prototipo (creando los métodos solo una vez), por lo tanto, dan acceso a esos métodos tanto para el nuevo volvo
como para el saab
.
// just mapping for less typing
Car.fn = Car.prototype;
Car.fn.drive = function () {
console.log("they see me rollin''");
};
Car.fn.honk = function () {
console.log("HONK!!!");
}
volvo.honk();
// => HONK!!!
saab.drive();
// => they see me rollin''