2013-08-12 4 views
81

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

Каковы наилучшие методы работы с ООП в 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 рассматриваться в качестве класса и модели, используемой в качестве экземпляра?)

EDIT

вот пример в 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) 
+9

В O. JS в node.js.s нет ничего особенного. Существует только OO JS. Ваш вопрос касается _translating_ Java OOP-технологий для JS, который просто не прав. Я думаю, что вам лучше было потратить время и силы на изучение того, как работает модель на основе прототипов JS, и как вы можете использовать ее в своих интересах. –

+1

Кроме того, у вас нет классов в JavaScript. Вы можете создавать поведение, подобное классу, с функциями, но, как правило, это не очень хорошая идея. –

+0

Что касается наследования, каждый метод, объявленный в прототипе, будет доступен экземплярами вашего объекта «Class», а также детьми класса «Class». –

ответ

97

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

Ну в файле 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; 
+0

В чем разница между использованием «Animal.prototype.getAge = function() {}» и просто добавлением 'this.getAge = function() { } 'inside' function Animal() {} '? Подкласс кажется немного взломанным .. с библиотекой «наследования» вы имеете в виду что-то вроде «наследуемых», как было предложено @badsyntax? – fusio

+4

@fusio да, вы можете сделать что-то вроде «inherits (Mouse, Animal)», который немного очищает наследование.Разница заключается в том, что вы создаете новый идентификатор функции для каждого объекта-объекта вместо совместного использования одной функции. Если у вас 10 мышей, вы создали 10 идентификаторов функций (это только потому, что у мыши есть один метод, если у нее было 10 методов, 10 мышей создавали бы 100 идентификаторов функций, ваш сервер быстро терял большую часть своего процессора на GC: P) , хотя вы не будете использовать их ни для чего. Язык не обладает достаточной выразительностью для оптимизации этого в настоящее время. – Esailija

+0

Woah. Спасибо :) Это кажется довольно простым, я также нашел [Details_of_the_Object_Model] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model), где они сравнивают JS с Java. Тем не менее, чтобы наследовать, они просто делают: 'Mouse.prototype = new Animal()' .. как он сравнивается с вашим примером? (например, что такое 'Object.create()'?) – fusio

14

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

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

+0

Это самый полезный ответ в отношении основной среды NodeJS. – Philzen

+0

Выглядит теперь не рекомендуется. Из ответа на ответ: * Примечание: использование утилиты util.inherits() не рекомендуется. Используйте класс ES6 и расширьте ключевые слова, чтобы получить поддержку наследования уровня языка. Также обратите внимание, что два стиля семантически несовместимы. * –

4

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

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

35

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

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

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

Ниже некоторые скелет класса, наследование написанном в Node.js (используется Node.js версия 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(); 
+0

Это лучший ответ для меня. Можем ли мы написать тест для классов? – kodmanyagha

6

Это бесц т видео о объектно-ориентированном JavaScript в Интернете:

The Definitive Guide to Object-Oriented JavaScript

Часы от начала до конца !!

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

С ES6 (выпущен 2015) мы получили «класс» ключевое слово, которое позволяет нам использовать JavaScript «классы», как мы бы с Java, C++, C#, Swift и т.д.

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

+0

Я ценю, что вы предоставили ответ для ES6. Спасибо! К сожалению, у меня нет данных для просмотра 27-минутного видео. Я продолжу поиск письменного руководства. –