2009-01-14 8 views
39

He estado usando javascript por un tiempo, pero nunca aprendí el idioma pasado los conceptos básicos. Estoy leyendo "Pro Javascript Techniques" de John Resig - Tengo algunas preguntas, pero no las encuentro en el libro o en google, etc.Preguntas orientadas a objetos en Javascript

John da este ejemplo en su libro :
Función # 1

function User(name, age){ 
    this.name = name; 
    this.age = age; 
} 
// Add a new function to the object prototype 
User.prototype.getName = function(){ 
    return this.name; 
}; 
User.prototype.getAge = function(){ 
    return this.age; 
}; 
var user = new User("Bob", 44); 
console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

todavía estoy aprendiendo sobre la propiedad prototipo, así que traté de escribir algo similar:
Función # 2

function User (name, age) { 
    this.name = name; 
    this.age = age; 
    this.getName = function() { 
    return this.name; 
    }; 
    this.getAge = function() { 
    return this.age; 
    }; 
} 
var user = new User("Bob", 44); 
console.log("User: " + user.getName() + ", Age: " + user.getAge()); 

que no utiliza el prototipo propiedad para crear las funciones getName y getAge, pero la salida es el mismo que el ejemplo de John.

Me tomó un paso más allá, y crearon esto:
Función # 3

var User = { 
    name: "", 
    age: 0, 
    setName: function(name) { 
    this.name = name; 
    }, 
    setAge: function(age) { 
    this.age = age; 
    }, 
    getName: function() { 
    return this.name; 
    }, 
    getAge: function() { 
    return this.age; 
    } 
}; 
User.setName("Bob"); 
User.setAge(44); 
console.log("User: " + User.getName() + ", Age: " + User.getAge()); 

Una vez más - se ve diferente que el ejemplo de Juan (y he tenido que añadir métodos setter), pero la salida es el mismo.

Pregunta # 1 - ¿Cuál es la diferencia entre las 3 funciones? ¿Cuál es la ventaja de la propiedad del prototipo, y la Función n. ° 2 está haciendo algo incorrectamente, porque parece más sencillo codificar # 2 en lugar de # 1 (aunque estoy seguro de que # 1 lo está haciendo mejor cuando John lo creó). .

Pregunta n. ° 2 - ¿Cómo podría modificar la función n. ° 3 para no utilizar los métodos setName y setAge, pero aun así conservar la {...} abreviatura? ¿Puede la {...} taquigrafía tener constructores?

Gracias de antemano por ayudarme a aprender!

EDIT Creo que mi segunda pregunta fue un poco confusa. Me refiero a cómo podría utilizar el {...} taquigrafía para crear un objeto de usuario, pero luego después de crear el objeto, diga algo como:

var user = new User("Bob", 44); 

Al igual que en la función # 1 - o es que no es posible ?

EDIT # 2 ¡Guau! Gracias a todos por las increíbles respuestas. Eso realmente lo hace mucho más claro para mí. Entonces, si entiendo correctamente, la diferencia entre # 1 y # 2 no es demasiado. Si solo alguna vez creo un objeto "Usuario", probablemente no sean diferentes en absoluto. Pero si mi programa crea muchos objetos de Usuario, lo más probable es que el # 1 sea más eficiente y use menos memoria ya que todos los objetos compartirán las mismas funciones.

Realmente aprecio todas las excelentes respuestas - ¡Gracias!

Respuesta

22

Cada vez que se evalúa una función() {}, crea un nuevo objeto de función. Por lo tanto, en el n. ° 1, todos los objetos User comparten las mismas funciones getName y getAge, pero en los n. ° 2 y n. ° 3, cada objeto tiene su propia copia de getName y getAge.Todas las diferentes funciones getName se comportan exactamente de la misma manera, por lo que no puede ver ninguna diferencia en el resultado.

La {...} abreviatura es un constructor. Cuando se evalúa, construye un nuevo "Objeto" con las propiedades dadas. Cuando ejecuta "nuevo Usuario (...)", construye un nuevo "Usuario". Usted ha creado un objeto con el mismo comportamiento que un usuario, pero son de diferentes tipos.

respuesta al comentario:

No se puede, directamente. Puede hacer una función que cree un nuevo objeto según # 3. Por ejemplo:

function make_user(name, age) { 
    return { 
     name: name, 
     age: age, 
     getName: function() { return name; }, 
     getAge: function() { return age; }, 
    }; 
} 

var user = make_user("Joe", "18"); 
+0

supongo que me refiero a la pregunta # 2 es ¿cómo puedo modificar la función # 3 para que yo pueda decir algo como var persona = new Usuario(); – BrianH

+0

Este comentario no es del todo cierto 'Todas las diferentes funciones getName se comportan exactamente igual'. Tipo # 2 tiene acceso a vars privados – meouw

+0

Mi punto es que se comportan igual en el ejemplo. – Glomek

5

2:

Puede acceder nombre y edad, sin necesidad de utilizar dichas funciones. En JavaScript tienes que usar diferentes hacks para mantener algo privado o protegido.

Este

User.name = "BoB"; 
User.age = 44; 

producirá misma salida que tu ejemplo.

No hay constructores como aparecen en otros idiomas. La forma más sencilla sería definir la función init() y llamarla justo después de instanciar el objeto.

Pero mi mayor consejo para usted es investigar http://www.prototypejs.org/. Es una biblioteca de JavaScript con muchas características geniales que intentan hacer javascript "más OO *".

Al utilizar la biblioteca de prototipos puede hacer que las clases se comporten más como clases OOP reales. También presenta constructores.

Editar: En cuanto a lo que usted pidió en su comentario:

person = new User(); 
person.name = "Bob"; 
person.age = 44; 
1

Pregunta # 1

prototype tiene la ventaja de monkey patching. Como muestra el primer ejemplo, la función se agrega después de los hechos. Puede continuar para agregar o reemplazar cualquier método que necesite (aunque con una advertencia justa).

La definición de objetos como # 2 es más parecida a la OOP clásica. Pero, una vez más, el parche de mono no está permitido en todos los lenguajes OOP.

Pregunta # 2

En su tercera función, ni siquiera necesita los get y set funciones - name y age son bienes de dominio público (el potencial a la baja para {}).

var User = { 
    name: "", 
    age: 0 
}; 

User.name = 'Bob'; 
User.age = 44; 

console.log("User: " + User.name + ", Age: " + User.age); 

Cuando se crea un objeto utilizando {} (un objeto literal), {} es el constructor (que varía en el navegador). Pero, esencialmente, no, no puedes usar un constructor en este formato.

+0

Agregar una propiedad o método a un objeto definido por el usuario no califica como parche de monos. El parche de mono está agregando métodos o propiedades a los objetos incorporados, es decir, cambiando el comportamiento del idioma en sí. – meouw

4

Su ejemplo n. ° 1 muestra el uso de la propiedad del prototipo.Esta propiedad está disponible para todos los objetos JavaScript que cree y le permite agregar propiedades o funciones a la declaración del objeto, por lo que tenía un objeto con 2 propiedades y luego agregó 4 funciones (getters y setters).

Debería ver la propiedad prototipo como la manera de modificar las especificaciones de objetos en tiempo de ejecución, supongamos que tiene un objeto denominado nombre:

var Name = { 
    First: "", 
    Last: "" 
}; 

Puede utilizar el prototipo añadir un getFullName función() más adelante simplemente:

Name.prototype.getFullName = function() { return this.First + " " + this.Last; } 

en el ejemplo 2 se Inline la declaración de estos captadores y definidores en la declaración objeto de tal manera que al final son los mismos. Finalmente, en el tercer ejemplo, use la notación de objetos de JavaScript, debería ver JSON.

Sobre su pregunta 2 sólo se puede declarar su objeto como:

var User = { 
    name: "", 
    age: 0 
}; 

esto le dará el mismo objeto sin captadores y definidores.

12

Si quieres hacer OOP en JavaScript, te sugiero buscar cierres. Empecé mi aprendizaje sobre el tema con estas tres páginas web:

http://www.dustindiaz.com/javascript-private-public-privileged/

http://www.dustindiaz.com/namespace-your-javascript/

http://blog.morrisjohns.com/javascript_closures_for_dummies

Las diferencias entre 1, 2 y 3 son los siguientes: 1) es una ejemplo de agregar nuevos métodos a un objeto existente. 2) Es lo mismo que # 1, excepto que algunos métodos están incluidos en el objeto en la función de Usuario. 3) Es un ejemplo de definición de un objeto usando JSON. El inconveniente es que no puede usar nuevo (al menos no con ese ejemplo) para definir nuevas instancias de ese objeto. Sin embargo, obtendrá el beneficio del conveniente estilo de codificación JSON.

Definitivamente debe leer en JSON si aún no lo sabe. JavaScript tendrá mucho más sentido cuando comprendas JSON.

edición Si desea utilizar la nueva función # 3 se puede escribir como

function User() { 
    return { 
    name: "", 
    age: 0, 
    setName: function(name) { 
     this.name = name; 
    }, 
    setAge: function(age) { 
     this.age = age; 
    }, 
    getName: function() { 
     return this.name; 
    }, 
    getAge: function() { 
     return this.age; 
    } 
    }; 
} 

Por supuesto, todas aquellas funciones y propiedades sería entonces pública. Para que sean privados, debes usar cierres. Por ejemplo, puede hacer que la edad y el nombre sean privados con esta sintaxis.

function User() { 
    var age=0; 
    var name=""; 
    return { 
    setName: function(name_) { 
     name = name_; 
    }, 
    setAge: function(age_) { 
     age = age_; 
    }, 
    getName: function() { 
     return name; 
    }, 
    getAge: function() { 
     return age; 
    } 
    }; 
} 
+1

Gracias por eso ... espero que todavía estés por aquí y respondiendo cosas en SO :) –

Cuestiones relacionadas