Varios modos de creación de objetos de uso común
Crear con nueva palabra clave
La forma más básica de crear objetos es más que lo que dicen la mayoría de los idiomas: si no tiene objetos, ¡puede obtener nuevo!
var gf = new Object (); gf.name = "tangwei"; gf.bar = "c ++"; gf.saywhat = function () {console.log (this.name+"triste: te amo para siempre");}Crear con literales
Esto parece ser cierto, pero ¿cómo pueden los geeks como una forma tan compleja y de bajo nivel de definir variables? Como lenguaje de secuencias de comandos, debe tener el mismo estilo que otros hermanos, por lo que aparece la forma de definir literales de objetos:
var gf = {name: "tangwei", bar: "c ++", diga qué: function () {console.log (this.name+"sad: te amo para siempre"); }}Modelo de fábrica
En realidad, este es el método de definición de objetos más comúnmente utilizado en la realidad, pero ¿qué debo hacer si tengo muchos objetos con atributos similares (es emocionante pensar en ello ...)? Si se hace una definición una por una, se generará una gran cantidad de código. ¿Por qué no construir una fábrica y producir masa nuestros objetos? Entonces, el primer bebé inflable en el mundo de JavaScript. . . ¡No, el "modelo de fábrica" nace!
function createGf (name, bar) {var o = new Object (); o.name = nombre; O.Bar = bar; o.saywhat = function () {alert (this.name + "Sad: te amo para siempre"); } return o;} var gf1 = createGf ("bingbing", "d"); var gf2 = createGf ("mimi", "a");Constructor
El patrón de fábrica resuelve el problema de crear múltiples objetos similares, pero el problema viene nuevamente. Todos estos objetos están formados por objetos. ¿Cómo distinguir los tipos específicos de sus objetos? En este momento, necesitamos cambiar a otro modo, modo constructor:
función gf (nombre, bar) {this.name = name; this.Bar = bar; this.saywhat = function () {alert (this.name + "dijo: te amo para siempre"); }} var gf1 = new Gf ("Vivian", "f"); var gf2 = new Gf ("Vivian2", "f");Aquí usamos un constructor que comienza con letras mayúsculas para reemplazar CreateGF en el ejemplo anterior. Tenga en cuenta que la primera letra del constructor debe capitalizarse de acuerdo con la Convención. Aquí creamos un nuevo objeto, luego asignamos el alcance del constructor al nuevo objeto y llamamos a los métodos en el constructor.
Parece que no hay nada de malo en el método anterior, pero podemos encontrar que el método Say que en el constructor llamado en las dos instancias no es la misma instancia de función:
console.log (gf1.saywhat == gf2.saywhat); //FALSO
Llamar al mismo método pero declarar diferentes instancias es un desperdicio de recursos. Podemos optimizar la declaración de la función Say que fuera del constructor:
función gf (nombre, bar) {this.name = name; this.Bar = bar; this.saywhat = say what} función dice qué () {alerta (this.name + "triste: te amo para siempre");}Esto resuelve el problema de definir la misma instancia de método varias veces, pero un nuevo problema vuelve a aparecer. El dicho de lo que definimos es un método de alcance global, pero este método no puede llamarse directamente, lo cual es un poco contradictorio. ¿Cómo definir más elegantemente un objeto con cierta encapsulación? Echemos un vistazo al patrón de objeto prototipo JavaScript.
Patrón de objeto prototipo
Comprender los objetos prototipo
Cuando creamos una función, la función tendrá un atributo prototipo, que apunta al objeto prototipo de la función creada a través del constructor. En términos de Layman, los objetos prototipo son objetos en la memoria que proporcionan propiedades y métodos compartidos para otros objetos.
En el modo prototipo, no es necesario definir los atributos de instancia en el constructor, y la información del atributo puede asignarse directamente al objeto prototipo:
function gf () {gf.prototype.name = "Vivian"; Gf.prototype.bar = "c ++"; Gf.prototype.saywhat = function () {alert (this.name + "sad: te amo para siempre"); }} var gf1 = new gf (); gf1.saywhat (); var gf2 = new gf ();La diferencia del constructor es que las propiedades y métodos del nuevo objeto pueden compartirse por todas las instancias. En otras palabras, GF1 y GF2 acceden a las mismas propiedades y métodos. Además de los atributos que hemos asignado, también hay algunos atributos incorporados en el objeto prototipo. Todos los objetos prototipo tienen un atributo de constructor, que es un puntero a una función que contiene el atributo prototipo (¡ya sea que se atreva a ir al punto nuevamente!). A través de una imagen, ordenemos claramente el proceso de esta torcer:
Todos los objetos tienen un objeto prototipo (prototipo). Hay un atributo de constructor en el objeto prototipo que apunta a una función que contiene el atributo prototipo. Las instancias de GF GF1 y GF2 contienen un atributo interno que apunta al objeto prototipo (Proto aparece como un atributo privado en el navegador Firefox). Cuando accedamos al atributo en un objeto, primero preguntaremos si el objeto de instancia tiene este atributo. Si no, continuaremos buscando el objeto prototipo.
Uso de objetos prototipo
En el ejemplo anterior, notamos que al agregar propiedades al objeto prototipo, necesitamos agregar gf.prototype a cada uno. Este trabajo es muy repetitivo. En el patrón de creación de objetos anterior, sabemos que se puede crear un objeto en forma de literales. Aquí también podemos mejorarlo:
function gf () {} gf.prototype = {name: "Vivian", bar: "c ++", diga qué: function () {alert (this.name+"sad: te amo para siempre"); }}Hay un lugar donde debemos prestar especial atención. El atributo del constructor ya no apunta al objeto GF, porque cada vez que se define una función, se creará un objeto prototipo para él al mismo tiempo, y este objeto obtendrá automáticamente un nuevo atributo de constructor. En este lugar, usamos GF.Prototype para sobrescribir esencialmente el objeto prototipo original, por lo que el constructor también se ha convertido en el atributo constructor del nuevo objeto, que ya no apunta a GF, sino objeto:
var gf1 = new gf (); console.log (gf1.constructor == gf); // Falseconsole.log (gf1.constructor == objeto) // Verdadero
En general, este cambio sutil no nos afectará, pero si tiene necesidades especiales de constructor, también podemos especificar explícitamente la propiedad del constructor de gf.prototype:
Gf.prototype = {constructor: gf, nombre: "Vivian", bar: "c ++", diga qué: function () {alert (this.name+"dijo: te amo para siempre"); }} var gf1 = new gf (); console.log (gf1.constructor == gf); // trueA través de una comprensión preliminar del patrón de objeto prototipo, encontramos que todos los objetos de instancias comparten los mismos atributos, que es la característica básica del patrón prototipo, pero a menudo esta es una "espada de doble filo" para los desarrolladores. En el desarrollo real, las instancias que esperamos deberían tener sus propios atributos, que también es la razón principal por la cual pocas personas usan el patrón prototipo solo en el desarrollo real.
Constructor y patrón de combinación de prototipos
En el desarrollo real, podemos usar constructores para definir las propiedades de los objetos y usar prototipos para definir propiedades y métodos compartidos, para que podamos pasar diferentes parámetros para crear diferentes objetos, mientras que tienen métodos y propiedades compartidas.
función gf (nombre, bar) {this.name = name; this.Bar = bar;} gf.prototype = {constructor: gf, diga qué: function () {alert (this.name + "sad: te amo para siempre"); }} var gf1 = new Gf ("Vivian", "f"); var gf2 = new Gf ("Vivian1", "c");En este ejemplo, definimos los valores de propiedades respectivos de los objetos en la función del constructor, y definimos el atributo del constructor y decimos qué función en el objeto prototipo, para que no haya impacto entre los atributos GF1 y GF2. Este patrón también es el método de definición de objetos más utilizado en el desarrollo real, incluido el modo predeterminado adoptado por muchas bibliotecas JS (Bootstrap, etc.).