Estoy acostumbrado a la POO clásica como en Java.
¿Cuáles son las mejores prácticas para hacer OOP en JavaScript usando NodeJS?
Cada clase es un archivo con module.export
?
¿Cómo crear clases?
this.Class = function() {
//constructor?
var privateField = ""
this.publicField = ""
var privateMethod = function() {}
this.publicMethod = function() {}
}
vs. (ni siquiera estoy seguro de que sea correcto)
this.Class = {
privateField: ""
, privateMethod: function() {}
, return {
publicField: ""
publicMethod: function() {}
}
}
vs.
this.Class = function() {}
this.Class.prototype.method = function(){}
...
¿Cómo funcionaría la herencia?
¿Existen módulos específicos para implementar OOP en NodeJS?
Estoy encontrando mil formas diferentes de crear cosas que se parezcan a POO ... pero no tengo ni idea de cuál es la forma más utilizada / práctica / limpia.
Pregunta adicional : ¿cuál es el "estilo OOP" sugerido para usar con MongooseJS? (¿se puede ver un documento MongooseJS como una clase y un modelo como instancia?)
EDITAR
aquí hay un ejemplo en JsFiddle, por favor envíe sus comentarios.
//http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/
function inheritPrototype(childObject, parentObject) {
var copyOfParent = Object.create(parentObject.prototype)
copyOfParent.constructor = childObject
childObject.prototype = copyOfParent
}
//example
function Canvas (id) {
this.id = id
this.shapes = {} //instead of array?
console.log("Canvas constructor called "+id)
}
Canvas.prototype = {
constructor: Canvas
, getId: function() {
return this.id
}
, getShape: function(shapeId) {
return this.shapes[shapeId]
}
, getShapes: function() {
return this.shapes
}
, addShape: function (shape) {
this.shapes[shape.getId()] = shape
}
, removeShape: function (shapeId) {
var shape = this.shapes[shapeId]
if (shape)
delete this.shapes[shapeId]
return shape
}
}
function Shape(id) {
this.id = id
this.size = { width: 0, height: 0 }
console.log("Shape constructor called "+id)
}
Shape.prototype = {
constructor: Shape
, getId: function() {
return this.id
}
, getSize: function() {
return this.size
}
, setSize: function (size) {
this.size = size
}
}
//inheritance
function Square(id, otherSuff) {
Shape.call(this, id) //same as Shape.prototype.constructor.apply( this, arguments ); ?
this.stuff = otherSuff
console.log("Square constructor called "+id)
}
inheritPrototype(Square, Shape)
Square.prototype.getSize = function() { //override
return this.size.width
}
function ComplexShape(id) {
Shape.call(this, id)
this.frame = null
console.log("ComplexShape constructor called "+id)
}
inheritPrototype(ComplexShape, Shape)
ComplexShape.prototype.getFrame = function() {
return this.frame
}
ComplexShape.prototype.setFrame = function(frame) {
this.frame = frame
}
function Frame(id) {
this.id = id
this.length = 0
}
Frame.prototype = {
constructor: Frame
, getId: function() {
return this.id
}
, getLength: function() {
return this.length
}
, setLength: function (length) {
this.length = length
}
}
/////run
var aCanvas = new Canvas("c1")
var anotherCanvas = new Canvas("c2")
console.log("aCanvas: "+ aCanvas.getId())
var aSquare = new Square("s1", {})
aSquare.setSize({ width: 100, height: 100})
console.log("square overridden size: "+aSquare.getSize())
var aComplexShape = new ComplexShape("supercomplex")
var aFrame = new Frame("f1")
aComplexShape.setFrame(aFrame)
console.log(aComplexShape.getFrame())
aCanvas.addShape(aSquare)
aCanvas.addShape(aComplexShape)
console.log("Shapes in aCanvas: "+Object.keys(aCanvas.getShapes()).length)
anotherCanvas.addShape(aCanvas.removeShape("supercomplex"))
console.log("Shapes in aCanvas: "+Object.keys(aCanvas.getShapes()).length)
console.log("Shapes in anotherCanvas: "+Object.keys(anotherCanvas.getShapes()).length)
console.log(aSquare instanceof Shape)
console.log(aComplexShape instanceof Shape)
prototype
cadena . Y no, el objeto no admite miembros " privados ". Solo los cierres pueden ofrecer eso, aunque los módulos / scripts en Node.js se implementan como cierres.Respuestas:
Este es un ejemplo que funciona fuera de la caja. Si quieres menos "hacky", debes usar la biblioteca de herencia o algo así.
Bueno, en un archivo animal.js escribirías:
Para usarlo en otro archivo:
Si desea una "subclase", dentro de mouse.js:
También puede considerar el "Método de préstamo" en lugar de la herencia vertical. No necesitas heredar de una "clase" para usar su método en tu clase. Por ejemplo:
fuente
Animal.prototype.getAge= function(){}
y simplemente agregarthis.getAge = function(){}
adentrofunction Animal() {}
? La subclase parece un poco hacky ... con la biblioteca de "herencia", ¿te refieres a algo comoinherits
lo sugerido por @badsyntax?inherits(Mouse, Animal);
limpiar un poco la configuración de herencia. La diferencia es que está creando una nueva identidad de función para cada objeto instanciado en lugar de compartir una función. Si tiene 10 ratones, ha creado 10 identidades de funciones (eso es solo porque el mouse tiene un método, si tuviera 10 métodos, 10 ratones crearían 100 identidades de funciones, su servidor desperdiciaría rápidamente la mayor parte de su CPU en GC: P) , aunque no los usarás para nada. El lenguaje no tiene suficiente poder expresivo para optimizar esto actualmente.Mouse.prototype = new Animal()
.. ¿cómo se compara con su ejemplo? (por ejemplo, ¿qué esObject.create()
?)Como la comunidad de Node.js, se asegura de que las nuevas características de la especificación JavaScript ECMA-262 lleguen a los desarrolladores de Node.js de manera oportuna.
Puedes echar un vistazo a las clases de JavaScript . Enlace MDN a clases JS En las clases de JavaScript ECMAScript 6 se introducen, este método proporciona una manera más fácil de modelar conceptos de POO en Javascript.
Nota : Las clases JS funcionarán solo en modo estricto .
A continuación se muestra el esqueleto de la clase, la herencia escrita en Node.js (versión usada de Node.js v5.0.0 )
Declaraciones de clase:
Herencia :
fuente
Sugiero usar el
inherits
ayudante que viene con elutil
módulo estándar : http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructorHay un ejemplo de cómo usarlo en la página vinculada.
fuente
Este es el mejor video sobre JavaScript orientado a objetos en Internet:
La guía definitiva para JavaScript orientado a objetos
¡Mira de principio a fin!
Básicamente, Javascript es un lenguaje basado en prototipos que es bastante diferente a las clases de Java, C ++, C # y otros amigos populares. El video explica los conceptos básicos mucho mejor que cualquier respuesta aquí.
Con ES6 (lanzado en 2015) obtuvimos una palabra clave de "clase" que nos permite usar "clases" de Javascript como lo haríamos con Java, C ++, C #, Swift, etc.
Captura de pantalla del video que muestra cómo escribir y crear una instancia de una clase / subclase de Javascript:
fuente
En la comunidad de Javascript, mucha gente argumenta que la POO no debería usarse porque el modelo prototipo no permite hacer una POO estricta y robusta de forma nativa. Sin embargo, no creo que la POO sea una cuestión de idioma, sino más bien una cuestión de arquitectura.
Si desea utilizar una POO realmente sólida en Javascript / Node, puede echar un vistazo al marco de código abierto de pila completa Danf . Proporciona todas las características necesarias para un código OOP sólido (clases, interfaces, herencia, inyección de dependencia, ...). También le permite utilizar las mismas clases en el lado del servidor (nodo) y del cliente (navegador). Además, puede codificar sus propios módulos danf y compartirlos con cualquiera gracias a Npm.
fuente
Si está trabajando por su cuenta y desea lo más parecido a OOP como lo encontraría en Java o C # o C ++, consulte la biblioteca de javascript, CrxOop. CrxOop proporciona una sintaxis algo familiar para los desarrolladores de Java.
Solo tenga cuidado, la POO de Java no es la misma que se encuentra en Javascript. Para obtener el mismo comportamiento que en Java, use las clases de CrxOop, no las estructuras de CrxOop, y asegúrese de que todos sus métodos sean virtuales. Un ejemplo de sintaxis es,
El código es javascript puro, sin transpiración. El ejemplo se toma de varios ejemplos de la documentación oficial.
fuente