¿Cuál es el prototipo?
El tipo de función tiene un prototipo de propiedad, que se traduce directamente al prototipo. Esta propiedad es un puntero, que apunta a un objeto, que contiene algunas propiedades y métodos, que serán compartidas por todas las instancias (objetos) generadas por la función actual.
Según lo que se dijo antes, puede obtener el siguiente código:
function persona () {...} persona.prototype = {país: 'China', sayname: function () {...}}Primero, se crea una persona de instancia de tipo de función, y luego el prototipo del método de la persona es un objeto, y la declaración apunta a un objeto. Las propiedades y métodos en este objeto serán compartidos por la instancia generada por la función de persona actual. Es decir:
persona1 = nueva persona (); persona2 = nueva persona ();
Person1 y Person2 se generan nuevamente a través de instancias de tipo de función de persona. Ambos tienen el país y el nombre de método de propiedad común, porque todos tienen un puntero (__proto__), señalando directamente al objeto señalado por persona.prototype. Sin embargo, tenga en cuenta que el puntero __proto__ no es estándar. Solo se define por navegadores como Chrome y Firefox. De hecho, esta propiedad no se utilizará, pero solo se usará como una comprensión del prototipo:
Con respecto al uso de prototipos y otros métodos, hablaremos de ello más específicamente más adelante.
Crear un patrón de objeto
A continuación, echemos un vistazo a los métodos y patrones comunes para crear objetos, así como sus ventajas y desventajas.
1. Modelo de fábrica
Al igual que una fábrica, el proceso de crear objetos concretos se abstrae, y las funciones se utilizan para encapsular los detalles de la creación de objetos con interfaces específicas. Mediante el uso de funciones en lugar de trabajo de repetición parcial, el código es el siguiente:
function createperson (nombre, edad, trabajo) {var o = nuevo objeto (); o.name = nombre; o.age = edad; o.job = trabajo; O.SayName = function () {alert (this.name); }; return o;} var persona1 = createperson ("jiangshui", "22", "ingeniero");Esto crea una persona, y el patrón de fábrica resuelve el problema de la creación repetida de múltiples objetos similares, pero no resuelve el problema de reconocimiento de objetos. Es solo que simplemente se crea un objeto, y no importa si este objeto se crea a partir de una plantilla humana o una plantilla de animales, es imposible distinguir el tipo de este objeto.
2. Modo constructor
Cree un constructor personalizado para definir propiedades y métodos de tipos de objetos personalizados.
Función persona (nombre, edad, trabajo) {this.name = name; this.age = edad; this.job = jpb; this.sayName = function () {alert (this.name); };}; var persona1 = nueva persona (...);3. La diferencia entre el modo de constructor y el modo de fábrica:
La persona es un objeto de tipo de función. Después de nuevo, se continuará generando un objeto. Sin embargo, dado que este objeto recién generado se pasa en la función y se asigna a este puntero, el contenido se transmite se convierte en propiedad o método del objeto recién generado.
El hábito predeterminado de los constructores se capitaliza en la primera letra. La ejecución del código anterior pasa por los siguientes pasos:
En los casos generados de esta manera, todos contienen un atributo de constructor de forma predeterminada apuntando a la función del constructor, por ejemplo:
alerta (persona1.constructor == persona);
Por lo tanto, utilizando el patrón del constructor, hay una distinción de tipo, y su instancia puede identificarse como un tipo específico.
Además, el constructor es una función ordinaria. Debido a que desea comentarios para obtener un nuevo objeto, usa nuevo para llamarlo. Si no, ejecutarlo directamente es como una función normal. Por ejemplo, si ejecuta persona.sayname () arriba, Window.ame aparecerá porque la función se ejecuta en la ventana, por lo que este punto a la ventana.
El modo de constructor también es defectuoso. Los métodos en el modo constructor se recrean en cada instancia, por lo que las funciones del mismo nombre en diferentes instancias no son iguales. Por ejemplo:
persona1.sayname == Person2.sayName; //FALSO
Es decir, cada instancia de objeto, atributos y métodos generados por el constructor son únicos y se copian. Los atributos son únicos, porque esta es exactamente la diferencia entre los objetos, pero muchos métodos tienen las mismas funciones y código. Si los copia repetidamente muchas veces, obviamente desperdiciará recursos.
Entonces podemos colocar la función afuera y luego señalar la función con un puntero en el constructor. En la instancia generada, el método almacena un puntero a una determinada función, lo que significa una función compartida:
Función Persona (nombre, edad) {this.name = name; this.age = edad; this.sayname = sayname;} function saysname () {alert (this.name);}Sin embargo, de esta manera, esta función se convierte en una función global, y no está altamente correlacionada con el constructor de personas y no tiene encapsulación.
A continuación, venga al modo prototipo.
Modo prototipo
Una parte de lo básico sobre prototipos se ha introducido anteriormente. En pocas palabras, cada función tiene un atributo prototipo, apuntando a un objeto (objeto prototipo), y algunas propiedades o métodos se pueden colocar en este objeto. Luego, la instancia generada por esta función tendrá un atributo irregular (__proto__) que apunta al prototipo.
Desde este punto de vista, debe poder comprender que las propiedades y los métodos generados por el prototipo son compartidas por todas las instancias.
Esto solo resuelve el problema de compartir funciones en el modo de constructor anterior y en los ejemplos. Por ejemplo, el siguiente código:
function persona () {....} persona.prototype.name = "jiangshui"; persona.prototype.sayname = function () {alert (this.name);}; var persona1 = nueva persona (); persona1.sayname (); // jiangshuio
Persona.prototype = {constructor: persona, nombre: "jiangshui", sayname: function () {alert (this.name); }};El segundo método cubre todo el objeto prototipo, por lo que debe especificar manualmente la propiedad del constructor, señalando la función del constructor, de lo contrario apuntará al objeto.
Ordenemos su relación:
Use isPrototypeOf () para determinar la relación entre objetos. Por ejemplo:
Persona.prototype.IsprototypeOf (persona1);
Cuando el código lee una determinada propiedad de un objeto, se realizará una búsqueda. Comience con el objeto actual y, si no, busque el objeto prototipo señalado por el puntero, sin buscar el constructor. Se puede acceder a la instancia del objeto, pero no puede anular el valor del objeto prototipo. Si se establece un atributo con el mismo nombre que el objeto prototipo en la instancia, el proceso de búsqueda termina en la instancia sin acceder al objeto prototipo, por lo que se logra el propósito de sobrescribir. Por lo tanto, incluso si esta propiedad está establecida en NULL, significa que la propiedad ya existe en la instancia, y la propiedad no se cancelará, de modo que se pueda acceder a la propiedad correspondiente del prototipo.
Por lo tanto, debe usar el operador Eliminar para eliminar completamente los atributos de instancia para que el prototipo pueda revisarse.
El prototipo es dinámico, y cualquier modificación realizada al objeto prototipo puede reflejarse inmediatamente de la instancia. La razón es la relación suelta del enlace entre la instancia y el prototipo. Cada vez que se llama al método de propiedad de la instancia, se realizará una consulta. Si el prototipo cambia, el resultado de la consulta también cambiará.
Después de comprender el prototipo, también podemos agregar nuevos métodos o atributos al objeto nativo. Los tipos de referencia nativos como el objeto, la matriz, la cadena, etc. son similares a los constructores anteriores. Podemos usar prototipo para expandir sus métodos. Por ejemplo:
String.prototype.startswith = function (text) {return this.indexof (text) == 0;}; var msg = "Hello World"; msg.Startswith ("Hello");Este código agrega un método Startswith a la cadena de tipo de referencia nativa, que es pasar en un parámetro para ver si la cadena a probar comienza con un parámetro. Debido a la naturaleza dinámica del prototipo, todas las variables del tipo de cadena obtienen este método ejecutándolo.
Sin embargo, este método no se recomienda. Si usa demasiado código, conducirá a dificultades de mantenimiento, confusión en el código, etc. En términos generales, se heredará primero un tipo de referencia nativo y luego se creará en un tipo recién personalizado. Con respecto a la herencia, la resumiremos más tarde.
El patrón prototipo tampoco es omnipotente. Todos los atributos y métodos en el prototipo son compartidos por todas las instancias, por lo que es muy adecuado para funciones y otras funciones, pero para los atributos que contienen tipos de referencia, surgirán algunos conflictos. Por ejemplo:
función persona () {} persona.prototype = {constructor: persona, amigos: ["greg", "jack"]}; var persona1 = nueva persona (); var persona2 = nueva persona (); persona1.fiends.push ("tom"); console.log (persona2.friends);Verá en la consola que hay un Tom adicional para Person2 Friends, que no es lo que quiero, pero al definir a su amigo a Person1, afecta a la persona de la instancia2.
Por lo tanto, necesitamos usarlo en combinación con patrón prototipo y patrón de constructor.
Use el modo constructor y el modo prototipo en combinación
Este es el patrón más utilizado. El constructor se utiliza para definir las propiedades de instancia y personalizar pasando parámetros; El prototipo se utiliza para definir métodos o atributos que requieren compartir entre todas las instancias. De esta manera, se logra la personalización, se garantiza el intercambio y se evitan los problemas.
Función persona (nombre, edad, trabajo) {this.name = name; this.age = edad; this.job = trabajo; this.friends = ["Greg", "Jack"];} Person.prototype = {constructor: persona, sayname: function () {alert (this.name); }}; var jiangshui = nueva persona ("jiangshui", "22", "ingeniero");Ejemplos de aplicaciones prácticas
Ok, aquí puede entender cuál es el prototipo y cómo crear objetos, pero ¿cuáles son los usos de estos? De hecho, mi trabajo anterior era solo escribir algún código usando jQuery, y no pude usar la encapsulación y luego generar objetos para implementar funciones, etc. Entonces, ¿cuáles son los usos de estos?
Este método de desarrollo se utiliza principalmente para el desarrollo modular y de ensamblaje. Por ejemplo, la función emergente que usa a menudo, por supuesto, puede pegar y copiar el código emergente cada vez, y luego modificarla y usarla en el proyecto. Una mejor opción es encapsular de manera abstracta su código de función emergente en dicho componente, de modo que cuando necesite usar ventanas emergentes, solo necesita pasar parámetros para generar una instancia emergente, y puede llamarlo.
Prototipo de objetos y cadenas prototipo
En JavaScript, todo es un objeto, pero también hay diferencias en los objetos. Se puede dividir aproximadamente en dos categorías, a saber: objetos ordinarios (objeto) y objetos de función (función).
En términos generales, los objetos generados a través de la nueva función son objetos de función, y otros objetos son objetos ordinarios.
Dar un ejemplo:
function f1 () {// tODO} var f2 = function () {// tODO}; var f3 = nueva función ('x', 'console.log (x)'); var o1 = {}; var o2 = new Object (); var o3 = new f1 (); console.log (typeof f1, // función typeof f2, // función typeof f3, // función typeof o1, // objeto typeof o2, // objeto typeof o3 // objeto); >> función objeto objeto objeto objetoF1 pertenece a la declaración de una función. La forma más común de definir una función es que F2 es en realidad una función anónima. Asigne esta función anónima a F2, que pertenece a una expresión de función. F3 no es común, pero también es un objeto de función.
La función es un objeto que viene con JS. Cuando se crean F1 y F2, JS construirá automáticamente estos objetos a través de la nueva función (). Por lo tanto, estos tres objetos se crean a través de la nueva función ().
Hay dos formas de crear objetos en JavaScript: literales de objetos y nuevas expresiones. La creación de O1 y O2 simplemente corresponde a estas dos formas. Centrémonos en O3. Si usa las ideas de Java y C# para comprender, O3 es un objeto de instancia de F1, y O3 y F1 son del mismo tipo. Al menos lo pensé antes, pero no es ...
Entonces, ¿cómo lo entiendes? Es muy simple. Vea si O3 se genera a través de una nueva función. Obviamente no. Como no es un objeto de función, es un objeto ordinario.
Después de una comprensión simple de los objetos de función y los objetos ordinarios, aprendamos sobre prototipos y cadenas prototipo en JavaScript:
En JS, cada vez que se crea un objeto de función F1, algunas propiedades están integradas en el objeto, incluidos el prototipo y __proto__, el prototipo es el objeto prototipo, que registra algunas propiedades y métodos de F1.
Cabe señalar que el prototipo es invisible para F1, es decir, F1 no buscará propiedades y métodos en el prototipo.
function f () {} f.prototype.foo = "ABC"; console.log (f.foo); //indefinidoEntonces, ¿de qué sirve el prototipo? De hecho, la función principal del prototipo es la herencia. En términos de Layman, las propiedades y métodos definidos en el prototipo se dejan a sus "descendientes", por lo que las subclases pueden acceder completamente a las propiedades y métodos en prototipo.
Para saber cómo F1 deja prototipos para "descendientes", necesitamos comprender la cadena prototipo en JS. En este momento, el __proto__ en JS ha ingresado al mercado. Este tipo es muy extraño y oculto, por lo que a menudo no lo ves, pero existe en objetos ordinarios y objetos de función. Su función es guardar el objeto prototipo de la clase principal. Cuando JS crea un objeto a través de una nueva expresión, generalmente asigna el prototipo de la clase principal al atributo __proto__ del nuevo objeto, que forma una generación de herencia ...
función f () {} f.prototype.foo = "ABC"; var obj = new f (); console.log (obj.foo); //abecedarioAhora sabemos que __proto__ en obj guarda el prototipo de F, entonces, ¿qué se guarda en __proto__ en el prototipo de F? Vea la siguiente imagen:
Como se muestra en la figura, el objeto.prototipo almacenado en el __proto__ de F.Prototype, y también hay __proto__ en el objeto Obj.prototype., Y desde el resultado de salida, el objeto.prototipo .__ Proto__ es nulo, lo que indica el final de la cadena Prototype de objeto OBJ. Como se muestra en la figura a continuación:
Después de que el objeto OBJ tiene una cadena de prototipo de este tipo, cuando OBJ.Foo se ejecuta, OBJ encontrará primero si tiene el atributo, pero no encontrará su propio prototipo. Cuando no se puede encontrar Foo, OBJ buscará a su vez la cadena prototipo ...
En el ejemplo anterior, definimos el atributo FOO en el prototipo de F, y luego OBJ encontrará este atributo en la cadena prototipo y lo ejecutará.