JavaScript OOP в NodeJS: как?

Я привык к классическому ООП, как в Java.

Каковы наилучшие методы работы ООП в JavaScript с помощью NodeJS?

Каждый класс является файлом с module.export?

Как создать классы?

this.Class = function() {
    //constructor?
    var privateField = ""
    this.publicField = ""
    var privateMethod = function() {}
    this.publicMethod = function() {} 
}

против. (Я даже не уверен, что это правильно)

this.Class = {
    privateField: ""
    , privateMethod: function() {}

    , return {
        publicField: ""
        publicMethod: function() {}
    }
}

против.

this.Class = function() {}

this.Class.prototype.method = function(){}

...

Как работает наследование?

Существуют ли определенные модули для реализации ООП в NodeJS?

Я нахожу тысячи разных способов создания вещей, которые напоминают ООП.. но я не знаю, что является наиболее используемым/практичным/чистым способом.

Бонусный вопрос: что такое предложенный "стиль ООП" для использования с MongooseJS? (может ли документ MongooseJS рассматриваться как класс и модель, используемая в качестве экземпляра?)

ИЗМЕНИТЬ

вот пример в JsFiddle, пожалуйста, предоставьте отзыв.

//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)

Ответ 1

Это пример, который работает из коробки. Если вы хотите меньше "взломать", вы должны использовать библиотеку наследования или таковую.

Ну в файле animal.js вы бы пишете:

var method = Animal.prototype;

function Animal(age) {
    this._age = age;
}

method.getAge = function() {
    return this._age;
};

module.exports = Animal;

Чтобы использовать его в другом файле:

var Animal = require("./animal.js");

var john = new Animal(3);

Если вам нужен "подкласс", то внутри mouse.js:

var _super = require("./animal.js").prototype,
    method = Mouse.prototype = Object.create( _super );

method.constructor = Mouse;

function Mouse() {
    _super.constructor.apply( this, arguments );
}
//Pointless override to show super calls
//note that for performance (e.g. inlining the below is impossible)
//you should do
//method.$getAge = _super.getAge;
//and then use this.$getAge() instead of super()
method.getAge = function() {
    return _super.getAge.call(this);
};

module.exports = Mouse;

Также вы можете рассмотреть "Заимствование метода" вместо вертикального наследования. Вам не нужно наследовать от "класса", чтобы использовать его метод для вашего класса. Например:

 var method = List.prototype;
 function List() {

 }

 method.add = Array.prototype.push;

 ...

 var a = new List();
 a.add(3);
 console.log(a[0]) //3;

Ответ 2

Сообщество Node.js гарантирует, что новые функции из спецификации JavaScript ECMA-262 будут своевременно представлены разработчикам Node.js.

Вы можете взглянуть на классы JavaScript. Ссылка MDN на классы JS В ECMAScript 6 введены классы JavaScript, этот метод обеспечивает более простой способ моделирования концепций ООП в Javascript.

Примечание: классы JS будут работать только в строгом режиме.

Ниже приведен некоторый скелет класса, наследование написанное в Node.js(используется Node.js Version v5.0.0)

Объявления класса:

'use strict'; 
class Animal{

 constructor(name){
    this.name = name ;
 }

 print(){
    console.log('Name is :'+ this.name);
 }
}

var a1 = new Animal('Dog');

Наследование:

'use strict';
class Base{

 constructor(){
 }
 // methods definitions go here
}

class Child extends Base{
 // methods definitions go here
 print(){ 
 }
}

var childObj = new Child();

Ответ 3

Я предлагаю использовать вспомогательный inherits, который поставляется со стандартным модулем util: http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

Существует пример того, как использовать его на связанной странице.

Ответ 4

Это лучшее видео об объектно-ориентированном JavaScript в Интернете:

Окончательное руководство по объектно-ориентированному JavaScript

Следите от начала до конца!

В принципе, Javascript является Prototype-based языком, который отличается от классов Java, С++, С# и других популярных друзей, Видео объясняет основные понятия намного лучше, чем любой ответ здесь.

С ES6 (выпущенный в 2015 году) мы получили ключевое слово "class", которое позволяет нам использовать "классы" Javascript, как в случае с Java, С++, С#, Swift и т.д.

Снимок экрана из видео, показывающего, как писать и создавать экземпляр класса/подкласса Javascript: enter image description here

Ответ 5

В сообществе Javascript многие люди утверждают, что ООП не следует использовать, потому что модель прототипа не позволяет делать строгий и надежный ООП изначально. Тем не менее, я не думаю, что ООП является вопросом языка, а скорее вопросом архитектуры.

Если вы хотите использовать реальный сильный ООП в Javascript/ Node, вы можете взглянуть на полноэкранную структуру с открытым исходным кодом Danf. Он предоставляет все необходимые функции для сильного кода ООП (классы, интерфейсы, наследование, зависимость-инъекция,...). Он также позволяет использовать те же классы как на стороне сервера (node), так и на стороне клиента (браузера). Кроме того, вы можете кодировать свои собственные модули danf и делиться ими с кем-либо благодаря Npm.