NodeJSでのJavaScript OOP:どうやって?


118

私はJavaのように古典的なOOPに慣れています。

NodeJSを使用してJavaScriptでOOPを実行するためのベストプラクティスは何ですか?

各クラスは、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にOOPを実装するための特定のモジュールはありますか?

私は、OOPに似たものを作成するための1000の異なる方法を見つけています。

おまけの質問: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)

12
node.jsには、OO JSに関する具体的なことは何もありません。OO JSがあります。あなたの質問は、Java OOP技術をJSに変換することですが、これは正しくありません。JSのプロトタイプベースのモデルがどのように機能するか、またそれをどのように利用できるかを学ぶのに同じ時間/エネルギーを費やした方がいいと思います
エリアスヴァンウーテゲム2013

1
また、JavaScriptにはクラスがありません。関数を使用してクラスのような動作を作成できますが、通常はお勧めできません。
m_vdbeek 2013

1
@AwakeZoldiek「ネイティブ機能」ではないとはどういう意味ですか?
エサイリヤ2013

4
@fusio一般的なプロトタイプ継承では、オブジェクト/インスタンスは他のオブジェクト/インスタンスから継承します。したがって、抽象定義を使用していないため、クラスは使用されません。したがって、継承はprototypeチェーンを介して行われます。そして、いいえ、オブジェクトは「プライベート」メンバーをサポートしていません。Node.jsのモジュール/スクリプトはクロージャーとして実装されていますが、クロージャーのみがそれを提供できます。
Jonathan Lonowski 2013

1
@Esailija閉鎖がプライベートメンバーを作成できることを示唆するつもりはありませんでした。クロージャーと囲まれた変数は、JavaScriptで取得できる限り同じであることを示唆していました。しかし、他の部分については、唯一の「実装」として、一部のグローバルが各スクリプトに固有に定義されているクロージャ内で評価される、考慮されたNodeモジュールについて言及しました。
Jonathan Lonowski 2013

回答:


116

これはそのまま使用できる例です。「ハック」を少なくしたい場合は、継承ライブラリなどを使用する必要があります。

ファイル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;

使用Animal.prototype.getAge= function(){}と単純にthis.getAge = function(){}内部を追加することの違いは何function Animal() {}ですか?サブクラスは少しハックに見えます。「継承」ライブラリを使用するとinherits、@ badsyntaxによって提案されたようなものを意味しますか?
fusio 2013

4
@fusioはい、inherits(Mouse, Animal);そのようなことを行うと、継承設定を少しクリーンアップできます。違いは、1つの関数を共有するのではなく、インスタンス化されたオブジェクトごとに新しい関数IDを作成することです。10個のマウスがある場合、10個の関数IDが作成されています(つまり、マウスに1つのメソッドがあるため、10個のメソッドがある場合、10個のマウスが100個の関数IDを作成し、サーバーはそのCPUのほとんどをGCですぐに浪費します:P) 、何にも使用しませんが。現在、この言語にはこれを最適化するのに十分な表現力がありません。
エサイリヤ2013

うわぁ。ありがとう:)これは非常に単純なようです。JSとJavaを比較するDetails_of_the_Object_Modelも見つけました。それでも、それらを継承するには、単に次のMouse.prototype = new Animal()ようにします。(例:何Object.create()ですか?)
fusio 2013

@fusio Object.createはコンストラクターを呼び出さない...コンストラクターに副作用などがある場合(Javaとは異なり、通常の関数でできることは何でも可能です)、継承チェーンを設定するときに呼び出すことは望ましくありません。
エサイリヤ2013

3
私はまだJavaScriptを使い始めている人のために、このようなソリューションをハッキングすることは良いソリューションではないことを維持しています。デバッグするのが簡単ではない癖や落とし穴がたくさんあるので、これは勧められません。
m_vdbeek 2013

43

Node.jsコミュニティにより、JavaScript ECMA-262仕様の新機能がNode.js開発者にタイムリーに提供されるようになります。

JavaScriptクラスを見てください。JSクラスへのMDNリンク ECMAScript 6 JavaScriptクラスに導入されたこのメソッドは、JavaScriptでOOPの概念をモデル化する簡単な方法を提供します。

:JSクラスは、strictモードでのみ機能します

以下は、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();

14

inherits標準utilモジュールに付属のヘルパーを使用することをお勧めします:http : //nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

リンク先のページに使用例があります。


これは、NodeJSコア環境に関して最も役立つ回答です。
Philzen

1
廃止予定になりました。回答リンクから:注:util.inherits()の使用はお勧めしません。言語レベルの継承サポートを取得するには、ES6クラスと拡張キーワードを使用してください。また、2つのスタイルには意味的に互換性がないことに注意してください。
Frosty Z

11

これは、インターネット上のオブジェクト指向JavaScriptに関する最高のビデオです。

オブジェクト指向JavaScriptの決定版ガイド

最初から最後まで見てください!!

基本的に、Javascriptはプロトタイプベースの言語であり、Java、C ++、C#、およびその他の人気のある友人のクラスとはかなり異なります。ビデオは、ここでの答えよりもはるかに優れたコアコンセプトを説明しています。

ES6(2015年にリリース)では、Java、C ++、C#、Swiftなどと同じようにJavascriptの「クラス」を使用できる「クラス」キーワードを取得しました。

JavaScriptクラス/サブクラスを作成してインスタンス化する方法を示すビデオのスクリーンショット: ここに画像の説明を入力してください


ES6の回答をお寄せいただきありがとうございます。ありがとうございました!残念ながら、27分のビデオを見るデータがありません。書面によるガイダンスを引き続き検索します。
tim.rohrer 2018

ビデオをありがとう。私は私がjavascriptについて持っていた多くの質問をクリアするのを助けました。
Kishore Devaraj 2018年

4

Javascriptコミュニティでは、プロトタイプモデルでは厳密で堅牢なOOPをネイティブに実行できないため、OOPを使用すべきではないと多くの人が主張しています。ただし、OOPは言語の問題ではなく、アーキテクチャの問題だと思います。

Javascript / Nodeで本当に強力なOOPを使用したい場合は、フルスタックのオープンソースフレームワークDanfをご覧ください。強力なOOPコードに必要なすべての機能(クラス、インターフェイス、継承、依存性注入など)を提供します。また、サーバー(ノード)側とクライアント(ブラウザー)側の両方で同じクラスを使用できます。さらに、独自のdanfモジュールをコーディングして、Npmのおかげで誰とでも共有できます。


-1

自分で作業していて、Java、C#、またはC ++で見られるようなOOPに最も近いものを必要とする場合は、JavaScriptライブラリCrxOopを参照してください。CrxOopは、Java開発者にはおなじみの構文を提供します。

注意してください、JavaのOOPはJavaScriptで見られるものと同じではありません。Javaと同じ動作を得るには、CrxOopの構造ではなくCrxOopのクラスを使用し、すべてのメソッドが仮想であることを確認します。構文の例は、

crx_registerClass("ExampleClass", 
{ 
    "VERBOSE": 1, 

    "public var publicVar": 5, 
    "private var privateVar": 7, 

    "public virtual function publicVirtualFunction": function(x) 
    { 
        this.publicVar1 = x;
        console.log("publicVirtualFunction"); 
    }, 

    "private virtual function privatePureVirtualFunction": 0, 

    "protected virtual final function protectedVirtualFinalFunction": function() 
    { 
        console.log("protectedVirtualFinalFunction"); 
    }
}); 

crx_registerClass("ExampleSubClass", 
{ 
    VERBOSE: 1, 
    EXTENDS: "ExampleClass", 

    "public var publicVar": 2, 

    "private virtual function privatePureVirtualFunction": function(x) 
    { 
        this.PARENT.CONSTRUCT(pA);
        console.log("ExampleSubClass::privatePureVirtualFunction"); 
    } 
}); 

var gExampleSubClass = crx_new("ExampleSubClass", 4);

console.log(gExampleSubClass.publicVar);
console.log(gExampleSubClass.CAST("ExampleClass").publicVar);

コードは純粋なjavascriptであり、変換は行われません。この例は、公式ドキュメントのいくつかの例から抜粋したものです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.