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() {} 
}

vs. (정확한지도 모르겠습니다)

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

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

this.Class = function() {}

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

...

상속은 어떻게 작동합니까?

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)

12
node.js의 OO JS에 대해 실제로 구체적인 것은 없습니다. OO JS 만 있습니다. 귀하의 질문에 관한 번역 그냥 JS, 자바 OOP 기술 하지 못했습니다를 . JS의 프로토 타입 기반 모델의 작동 방식과이를 활용하는 방법을 배우는 데 동일한 시간 / 에너지를 소비하는 것이 더 낫다고 생각합니다
Elias Van Ootegem 2013 년

1
또한 JavaScript에는 클래스가 없습니다. 함수를 사용하여 클래스와 같은 동작을 만들 수 있지만 일반적으로 좋은 생각은 아닙니다.
m_vdbeek 2013-08-12

1
@AwakeZoldiek "네이티브 기능"이 아니라는 것은 무엇을 의미합니까?
Esailija

4
@fusio 일반적으로 프로토 타입 상속을 사용하면 개체 / 인스턴스가 다른 개체 / 인스턴스에서 상속됩니다. 따라서 추상 정의로 작업하지 않기 때문에 클래스가 사용되지 않습니다. 따라서 상속은 prototypechain을 통해 이루어집니다 . 그리고 개체는 " private "멤버를 지원하지 않습니다 . 만 폐쇄는 모듈 / Node.js를에서 스크립트가 폐쇄로 구현되어 있지만, 그것을 제공 할 수 있습니다.
Jonathan Lonowski 2013-08-12

1
@Esailija 실제로 폐쇄가 비공개 회원을 만들 수 있다고 제안하려는 것은 아닙니다. 클로저와 동봉 된 변수가 JavaScript에서 얻을 수 있는 것만 큼 ​​가깝다 는 것을 제안했습니다 . 그러나 다른 부분의 경우 : 내가 언급 한 유일한 " 구현 "은 일부 전역 이 각 스크립트에 고유하게 정의 되는 클로저 내에서 평가되는 Node 모듈을 언급했습니다 .
Jonathan Lonowski는

답변:


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-08-12

4
@fusio 예, inherits(Mouse, Animal);상속 설정을 약간 정리하는 것과 같은 작업을 수행 할 수 있습니다 . 차이점은 하나의 함수를 공유하는 대신 인스턴스화 된 각 개체에 대해 새 함수 ID를 만드는 것입니다. 10 개의 마우스가있는 경우 10 개의 기능 ID를 생성 한 것입니다 (즉, 마우스가 하나의 방법을 가지고 있기 때문에 10 개의 방법이있는 경우 10 개의 마우스가 100 개의 기능 ID를 생성하고 서버는 GC : P에서 대부분의 CPU를 빠르게 낭비하게됩니다) , 비록 당신이 아무것도 사용하지 않더라도. 이 언어는 현재이를 최적화 할 충분한 표현력이 없습니다.
Esailija 2013-08-12

와. 감사합니다 :) 이것은 매우 간단 해 보입니다. 또한 JS를 Java와 비교하는 Details_of_the_Object_Model 을 발견 했습니다 . 그래도 상속하려면 Mouse.prototype = new Animal()다음과 같이합니다 . .. 귀하의 예와 어떻게 비교됩니까? (무엇 예를 들면 Object.create()?)
fusio

@fusio Object.create는 생성자를 호출하지 않습니다 ... 생성자에 부작용 등이있는 경우 (Java와 달리 일반 함수가 할 수있는 모든 작업을 수행 할 수 있음) 상속 체인을 설정할 때 호출하는 것은 바람직하지 않습니다.
Esailija 2013-08-12

3
나는 여전히 JavaScript를 사용하기 시작한 누군가에게 이와 같은 솔루션을 해킹하는 것은 좋은 솔루션이 아니라고 유지합니다. 디버그하기 쉽지 않은 단점과 함정이 너무 많아서 권장해서는 안됩니다.
m_vdbeek 2013-08-12

43

Node.js 커뮤니티는 JavaScript ECMA-262 사양의 새로운 기능이 적시에 Node.js 개발자에게 제공되도록 보장합니다.

JavaScript 클래스를 살펴볼 수 있습니다 . JS 클래스 에 대한 MDN 링크 ECMAScript 6 JavaScript 클래스가 도입되면이 방법은 Javascript에서 OOP 개념을 모델링하는 더 쉬운 방법을 제공합니다.

참고 : 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();

14

inherits표준 util모듈 과 함께 제공 되는 도우미 를 사용하는 것이 좋습니다 . http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor

링크 된 페이지에 사용 방법의 예가 있습니다.


이것은 핵심 NodeJS 환경과 관련하여 가장 유용한 답변입니다.
Philzen

1
이제 더 이상 사용되지 않는 것 같습니다. 답변 링크에서 : 참고 : util.inherits () 사용은 권장되지 않습니다. ES6 클래스를 사용하고 키워드를 확장하여 언어 수준 상속 지원을 받으십시오. 또한 두 스타일은 의미 상 호환되지 않습니다.
Frosty Z

11

이것은 인터넷에서 객체 지향 JavaScript에 대한 최고의 비디오입니다.

객체 지향 JavaScript에 대한 확실한 가이드

처음부터 끝까지보세요 !!

기본적으로 Javascript는 Java, C ++, C # 및 기타 인기있는 친구의 클래스와는 매우 다른 프로토 타입 기반 언어입니다. 비디오는 여기에있는 어떤 대답보다 핵심 개념을 훨씬 더 잘 설명합니다.

ES6 (2015 년 출시)에서는 Java, C ++, C #, Swift 등과 같이 Javascript "클래스"를 사용할 수있는 "class"키워드를 얻었습니다.

자바 스크립트 클래스 / 하위 클래스를 작성하고 인스턴스화하는 방법을 보여주는 비디오의 스크린 샷 : 여기에 이미지 설명 입력


ES6에 대한 답변을 제공해 주셔서 감사합니다. 감사합니다! 안타깝게도 27 분짜리 동영상을 볼 데이터가 없습니다. 나는 서면 지침을 계속 검색 할 것입니다.
tim.rohrer

비디오 감사합니다. 저는 제가 자바 스크립트에 대해 가지고있는 많은 질문을 해소하는 데 도움을주었습니다.
Kishore Devaraj

4

자바 스크립트 커뮤니티에서 많은 사람들은 프로토 타입 모델이 기본적으로 엄격하고 강력한 OOP를 수행 할 수 없기 때문에 OOP를 사용해서는 안된다고 주장합니다. 그러나 나는 OOP가 언어의 문제가 아니라 아키텍처의 문제라고 생각합니다.

Javascript / Node에서 진정한 강력한 OOP를 사용하려면 풀 스택 오픈 소스 프레임 워크 인 Danf를 살펴볼 수 있습니다. 강력한 OOP 코드 (클래스, 인터페이스, 상속, 종속성 주입 등)에 필요한 모든 기능을 제공합니다. 또한 서버 (노드) 및 클라이언트 (브라우저) 측 모두에서 동일한 클래스를 사용할 수 있습니다. 또한 Npm 덕분에 자신 만의 danf 모듈을 코딩하고 누구와도 공유 할 수 있습니다.


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

코드는 순수한 자바 스크립트이며 트랜스 파일이 아닙니다. 이 예제는 공식 문서의 여러 예제에서 가져 왔습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.