NodeJS中的JavaScript OOP:怎么样?

fus*_*sio 106 javascript oop inheritance mongoose node.js

我习惯于Java中的经典OOP.

使用NodeJS在JavaScript中进行OOP的最佳实践是什么?

每个Class都是一个文件module.export

如何创建类?

this.Class = function() {
    //constructor?
    var privateField = ""
    this.publicField = ""
    var privateMethod = function() {}
    this.publicMethod = function() {} 
}
Run Code Online (Sandbox Code Playgroud)

vs.(我甚至不确定它是否正确)

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

    , return {
        publicField: ""
        publicMethod: function() {}
    }
}
Run Code Online (Sandbox Code Playgroud)

this.Class = function() {}

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

...
Run Code Online (Sandbox Code Playgroud)

继承如何工作?

是否有在NodeJS中实现OOP的特定模块?

我发现了一千种不同的方法来创造类似于OOP的东西..但我不知道最常用/实用/干净的方式是什么.

奖金问题:与MongooseJS一起使用的建议"OOP风格"是什么?(可以将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)
Run Code Online (Sandbox Code Playgroud)

Esa*_*ija 112

这是一个开箱即用的示例.如果你想减少"hacky",你应该使用继承库等.

好吧,在文件animal.js中你会写:

var method = Animal.prototype;

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

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

module.exports = Animal;
Run Code Online (Sandbox Code Playgroud)

要在其他文件中使用它:

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

var john = new Animal(3);
Run Code Online (Sandbox Code Playgroud)

如果你想要一个"子类",那么在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;
Run Code Online (Sandbox Code Playgroud)

您也可以考虑"方法借用"而不是垂直继承.您不需要从"类"继承以在您的类上使用其方法.例如:

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

 }

 method.add = Array.prototype.push;

 ...

 var a = new List();
 a.add(3);
 console.log(a[0]) //3;
Run Code Online (Sandbox Code Playgroud)

  • @fusio是的,你可以做一些像`inherits(Mouse,Animal);`来清理继承设置的东西.不同之处在于您为每个实例化对象创建新的功能标识,而不是共享一个功能.如果你有10只老鼠,你已经创建了10个功能标识(这只是因为鼠标有一种方法,如果它有10种方法,10只老鼠会产生100个功能标识,你的服务器会很快浪费掉它在GC上的大部分CPU:P) ,即使你不会用它们做任何事情.目前,该语言没有足够的表现力来优化它. (4认同)
  • 我仍然坚持认为,对于那些开始使用JavaScript的人来说,破解这样的解决方案并不是一个好的解决方案.有太多的怪癖和陷阱不容易调试,不应该建议这样做. (3认同)

Piy*_*gar 41

Node.js社区确保将JavaScript ECMA-262规范中的新功能及时提供给Node.js开发人员.

你可以看看JavaScript类.链接到JS类的MDN 在ECMAScript中引入了6个JavaScript类,这个方法提供了在Javascript中模拟OOP概念的更简单方法.

注意:JS类只能在严格模式下工作.

下面是一些类的骨架,用Node.js编写的继承(Used 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');
Run Code Online (Sandbox Code Playgroud)

继承:

'use strict';
class Base{

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

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

var childObj = new Child();
Run Code Online (Sandbox Code Playgroud)


bad*_*tax 14

我建议使用inherits标准util模块附带的帮助器:http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

有一个如何在链接页面上使用它的示例.


eta*_*luz 9

这是关于互联网上面向对象JavaScript的最佳视频:

面向对象JavaScript的权威指南

从头到尾观看!!

基本上,Javascript是一种基于Prototype的语言,它与Java,C++,C#和其他流行朋友中的类完全不同.该视频解释了核心概念,远胜于此处的任何答案.

使用ES6(2015年发布),我们得到了一个"class"关键字,它允许我们像使用Java,C++,C#,Swift等一样使用Javascript"类".

显示如何编写和实例化Javascript类/子类的视频的屏幕截图: 在此输入图像描述


Gnu*_*cki 5

在 Javascript 社区中,很多人认为不应该使用 OOP,因为原型模型本身不允许执行严格且健壮的 OOP。然而,我不认为 OOP 是一个语言问题,而是一个架构问题。

如果你想在 Javascript/Node 中使用真正强大的 OOP,可以看看全栈开源框架Danf。它提供了强大的 OOP 代码所需的所有功能(类、接口、继承、依赖注入……)。它还允许您在服务器(节点)和客户端(浏览器)端使用相同的类。此外,借助 Npm,您可以编写自己的 danf 模块并与任何人分享。