124 votes

JavaScript OOP dans NodeJS : comment ?

Je suis habitué à la POO classique comme dans Java.

Quelles sont les meilleures pratiques pour faire de la POO en JavaScript en utilisant NodeJS ?

Chaque classe est un fichier avec module.export ?

Comment créer des classes ?

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

vs. (je ne suis même pas sûr que ce soit correct)

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

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

vs.

this.Class = function() {}

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

...

Comment fonctionne l'héritage ?

Existe-t-il des modules spécifiques pour implémenter la POO dans NodeJS ?

Je trouve un millier de façons différentes de créer des choses qui ressemblent à la POO mais je n'ai aucune idée de la façon la plus utilisée/pratique/propre.

Question bonus : quel est le "style de POO" suggéré à utiliser avec MongooseJS ? (un document MongooseJS peut-il être vu comme une classe et un modèle utilisé comme une instance) ?

EDIT

Voici un exemple en JsFiddle veuillez fournir des commentaires.

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

120voto

Esailija Points 74052

Il s'agit d'un exemple qui fonctionne dès le départ. Si vous voulez moins de "bricolage", vous devriez utiliser une bibliothèque d'héritage ou autre.

Eh bien, dans un fichier animal.js, vous écrirez :

var method = Animal.prototype;

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

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

module.exports = Animal;

Pour l'utiliser dans un autre fichier :

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

var john = new Animal(3);

Si vous voulez une "sous classe", alors dans 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;

Vous pouvez également envisager "l'emprunt de méthodes" au lieu de l'héritage vertical. Vous n'avez pas besoin d'hériter d'une "classe" pour utiliser sa méthode dans votre classe. Par exemple :

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

 }

 method.add = Array.prototype.push;

 ...

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

51voto

Piyush Sagar Points 1378

En tant que communauté Node.js, assurez-vous que les nouvelles fonctionnalités de la spécification JavaScript ECMA-262 sont apportées aux développeurs Node.js en temps voulu.

Vous pouvez jeter un coup d'œil à Classes JavaScript . Lien MDN vers les classes JS Dans l'ECMAScript 6, les classes JavaScript sont introduites, cette méthode fournit un moyen plus facile de modéliser les concepts de la POO en Javascript.

Note : Les classes JS ne fonctionneront que dans mode strict .

Ci-dessous, un squelette de classe, d'héritage écrit en Node.js (version Node.js utilisée). v5.0.0 )

Déclarations de classes :

'use strict'; 
class Animal{

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

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

var a1 = new Animal('Dog');

Héritage :

'use strict';
class Base{

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

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

var childObj = new Child();

14voto

badsyntax Points 4441

Je suggère d'utiliser le inherits qui est fourni avec l'assistant standard util module : http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

Vous trouverez un exemple d'utilisation sur la page liée.

13voto

etayluz Points 175

Il s'agit de la meilleure vidéo sur le JavaScript orienté objet sur Internet :

Le guide définitif du JavaScript orienté objet

Regardez du début à la fin !

En gros, le Javascript est un Basé sur des prototypes qui est très différent des classes de Java, C++, C# et autres amis populaires. La vidéo explique les concepts de base bien mieux que toute réponse ici.

Avec ES6 (sortie en 2015), nous avons obtenu un mot-clé "class" qui nous permet d'utiliser des "classes" Javascript comme nous le ferions avec Java, C++, C#, Swift, etc.

Capture d'écran de la vidéo montrant comment écrire et instancier une classe/sous-classe Javascript : enter image description here

5voto

Gnucki Points 3765

Dans la communauté Javascript, beaucoup de gens soutiennent que la POO ne devrait pas être utilisée parce que le modèle prototype ne permet pas de faire une POO stricte et robuste de manière native. Cependant, je ne pense pas que la POO soit une question de langage mais plutôt une question d'architecture.

Si vous voulez utiliser une méthode de programmation orientée objet (POO) vraiment solide en Javascript/Node, vous pouvez jeter un coup d'œil au framework open source complet Danf . Il fournit toutes les fonctionnalités nécessaires pour un code POO fort (classes, interfaces, héritage, injection de dépendances, ...). Il vous permet également d'utiliser les mêmes classes à la fois du côté serveur (nœud) et du côté client (navigateur). De plus, vous pouvez coder vos propres modules danf et les partager avec tout le monde grâce à Npm.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X