2012-04-02 5 views
4

자바 스크립트에서 OO 프로그래밍을 배우고 있으며 클래스를 만드는 방법이 많이 있습니다. 나는 일반 구조로 읽은 것들을 많이 뽑아 냈지만 프로토 타이핑의 목적이 부 풀림을 피하기 위해 누락 된 것 같았습니다. 이 "클래스"의 프로토 타입 정의를 포함하면 객체가 줄어들지 않습니다 (즉, 객체 크기가 줄어들지 않음)? 이 전체 구조에 결함이 있습니까?자바 스크립트의 적절한 클래스 구성

감사합니다,

var Car = (function() { 

    //Private fields 
    var _make; 
    var _model; 

    //Constants (protected by encapsulation)  
    var NUM_OF_WHEELS = 4; 

    //Private methods 
    function getDesc() { 
     return _make + " " + _model; 
    } 

    //Public constructor 
    function thisCar(make, model, color) { 
     _make = make; 
     _model = model; 

     //public properties 
     thisCar.prototype.color = color; 
    } 

    //static properties 
    thisCar.carsInTheWorld = 50; 

    //static methods 
    thisCar.getNumberOfWheels = function() { 
     return NUM_OF_WHEELS * thisCar.carsInTheWorld; 
    }; 

    //public properties 
    thisCar.prototype.color = ""; 

    //public method 
    thisCar.prototype.startEngine = function() { 
     console.log(getDesc() + " engine started"); 
    }; 

    return thisCar; 
})(); 

코멘트를 읽은 후 편집 여기에 제공된 링크는 내가 이해입니다.

개인 멤버에 대한 액세스가 필요한 클래스의 멤버는 프로토 타입에 추가 할 수 없으며 권한이 있어야합니다. 또한 프로토 타입을 생성자 함수에 포함하지 않는 것이 일반적입니다.

var Car = function (make, model, color) {//Public constructor 
    //Private fields 
    var _make = make; 
    var _model = model; 

    //Public fields 
    this.color = color; 

    //Private methods 
    function getDesc() { 
     return _make + " " + _model; 
    } 

    //Privileged functions (requiring private members) 
    this.startEngine = function() { 
     console.log(getDesc() + " engine started"); 
    }; 
}; 

//public method 
Car.prototype.sprayPaint = function (newColor) { 
    var oldColor = this.color; 
    this.color = newColor; 
    console.log("Your car has changed from " + oldColor + " to " + newColor); 
}; 

//Public fields (if not declared in constuctor) 
Car.prototype.fuel = 0; 

//static properties 
Car.carsInTheWorld = 0; 

//static methods 
Car.getNumberOfWheels = function() {    
    var NUM_OF_WHEELS = 4; 
    return NUM_OF_WHEELS * Car.carsInTheWorld; 
}; 

모든 답변을 주셔서 감사합니다.

+3

개인적으로 JS에서 이런 종류의 코딩은 나를 싫어하게 만듭니다. 엄청나게 역동적 인 언어이고, 당신 말이 맞습니다. 모든 것을 할 수있는 많은 방법이 있습니다. 필자는 결국 클래스 프레임 워크 (예 : JS.Class)를 사용하게 될 것이라고 절망적으로 생각합니다. –

+3

코드에 많은 문제가 있습니다. 자세한 내용을 보려면 여기를 클릭하십시오. 당신은 내 JS JS * 올바른 * 상속에 대한 유형에 대한 게시물을 볼 수 있습니다 http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html –

+0

코드를보고 솔직히, 당신은 [MDN] (https : //developer.mozilla.org/ko/JavaScript/Introduction_to_Object-Oriented_JavaScript) 객체 지향 자바 스크립트 – Starx

답변

0

대부분이 문제가 없습니다. 그래도이 비트는 틀린 것입니다.

생성자 안에는 프로토 타입에 아무 것도 지정하지 마십시오. 그러면 생성자에서 생성 된 모든 Cars에 color 속성이 할당됩니다.

대신,이 작업을 수행합니다

this.color = color; 

그리고 일반적인 질문에 대답하기 위해, 프로토 타입이 방법을 사용하는 의미가 없습니다. 외부 함수는 스크립트가 파싱 된 직후 한 번만 실행됩니다. 내부 thisCar 생성자를 Car에 할당합니다. 위에서 언급 한 예외 사항을 제외하고 프로토 타입 속성은 올바르게 배치됩니다.

다른 제안 사항은 내부적으로 IIFE의 내부에도 이름에 대문자를 사용해야한다는 것입니다. 개인적으로 여기에 Car을 사용하는 것이 더 명확 해 보입니다.

편집 :

처음에는 내가 본 것보다 더 많이 잘못되었습니다. 이것은 또한 잘못되었습니다

var _make; 
var _model; 

// [ ... ] 
function thisCar(make, model, color) { 
    _make = make; 
    _model = model; 
} 

이들은 인스턴스 속성이 아닙니다.

또한, 프로토 타입을 클로저 기반 개인 속성과 함께 사용하는 방법을 실제로 알 수있는 방법은 없습니다. 그래서 너는 너무 많은 것을하려고하는 것 같아. 대신 프로토 타입을 사용

3

는 일반적인 패턴은 공개 접근/뮤 테이터가 들어있는 생성자에서 개체를 반환하는 것입니다 :

jsfiddle

function Car() { 
    var myPrivateVar = "foo"; 
    var myPublicVar = "bar"; 

    function myPrivateFunc() {console.log(myPrivateVar);}; 
    myPrivateFunc();  

    return { 
    getMyPublicVar: function() { 
     return myPublicVar; 
    } 
    } 
} 
var honda = Car(); 
console.log(honda.getMyPublicVar()); 
honda.myPrivateFunc(); // fail 
속성을 추가 할 수있는 클래스 정의 외부

를 사용하여 프로토 타입 그것에.Car이 이미 정의되어 있고 myFunc ~ Car 개의 개체가 나중에 인스턴스화 된 후에 Car.prototype.myFunc = function() {};을 사용합니다.추가 된 회원은 공개됩니다.

Here's a question that should help you

Here's the standard article from Crockford on doing inheritance this way.

난 당신의 코드가 커질 때 클래스 프레임 워크와 같은 JS.Class을 사용하여 당신에게 수많은 두통을 절약 할 수 있음을 반복한다

.

+0

아니요. 생성자는 객체를 반환하지 않아야합니다. – Bergi

+0

죄송합니다. 제 구조는 약간 잘못되었습니다. 이것은 생성자가 아니며 "생성자"입니다. OO 의미에서, 당신은'new Car()'를 호출하지 않는다는 점에서 기술적 인 JavaScript 의미는 아닙니다. 그러나 여전히 Car()에서 반환되는 개인 정보 및 인터페이스를 가질 수있는 클로저를 만듭니다. –

+0

생성자 또는 함수로 호출 할 수있는 많은 네이티브 JS 생성자가 있습니다. 예를 들어 문자열. return 문을 분기하는 것이 좋은 생각이지만, 반환 시점에 프로세스를 중지하는 것 이외의 객체 인스턴스화에는 아무런 영향이 없다고 생각합니다. –

2

클로저와 객체 지향 생성자를 혼합했습니다. 보통, 당신은 종결없이 시작합니다. JS에서는 생성자 함수로 "클래스"를 정의합니다.

var Car = function Car(model) { //Public constructor 

    // Private fields of one instance 
    // model is an argument 
    var make; 

    // Private methods of one instance 
    function getDesc() { 
     return make + " " + model; 
    } 

    // Public fields of one instance 
    this.color = "#555"; 

    // Public methods of one instance, privileged the access private fields and functions 
    this.setMake = function(m) { 
     make = m; 
    }; 
    this.desc = function() { 
     return getDesc(); 
    }; 
} // end of constructor 

/* now the prototype things: */ 

// public "default" fields, may get overwritten per instance 
Car.prototype.color = ""; 

// public methods, can only access other public things (not "privileged") 
thisCar.prototype.startEngine = function() { 
    console.log(this.desc() + " engine started"); 
}; 

그게 전부입니다. 이제 정적 인 것들을 추가 할 수 있습니다. 그것들은 Car 함수와 아무 관련이 없지만 종종 그들은 생성자의 속성에 의해 네임 스페이스를 갖습니다. 그러나 그들은 또한 자유 변수가 될 수 있습니다.

var carsInTheWorld = 50; 
// or 
Car.livingInstances = 50; 
// or something 

Car.NUM_OF_WHEELS = 4; // constants are uppercase 

정적, 개인 변수가 필요한 경우에만 - 예 : 인스턴스 카운터 - 당신은 모든 것을 막을 수 있습니다. 그런 다음 unnamespaced 변수는 해당 클로저 함수 내부에서만 액세스 할 수 있습니다.

+0

this.desc는 본질적으로 비공개가 아닌 getDesc()를 노출합니다. 내 문제는 여기에 프로토 타입과 개인 메서드/변수에 메서드를 추가하는 방법을 혼용 할 수 없다고 생각합니다. – Phillip

+0

예,이 예에서는'this.desc = getDesc; '와 거의 같습니다. 그러나 나는 단지 특권이 부여 된 개인 기능의 사용을 보여 주기만을 원했습니다. 다른 예제 추가. – Bergi

2

프로토 타입을 인스턴스 생성자 함수에 직접 첨부 된 메소드의 백업 저장소로 생각하십시오. 인스턴스가없는 인스턴스에서 속성/메서드를 호출하려고하면 해당 인스턴스의 생성자의 프로토 타입이 메서드에 대해 검사됩니다. 실마리는 프로토 타입 속성이 인스턴스 내부를 볼 수 없다는 것입니다 (인스턴스 변수에 액세스).

복잡한 클래스와 같은 상속 체계를 허용하기 위해 프로토 타입을 연결하는 라이브러리를 즉각적으로 피하는 것이 좋습니다.

이 접근법은 악취가납니다. 유연하지 않고 읽기가 어렵고 JS가 처음부터 잘 다루는 문제에 적합하지 않습니다. (실제로 그러한 계획은 과장되어 어떤 언어로든 권장되지 않습니다.) 나는 상속이 나쁘지 않다는 것을 말하지 않고있다. 자바 스크립트의 성배는 나쁜 자바를 작성하지 않는다는 것을 의미한다. 나는 20 일 동안 계단식 상속을 완전히 이해할 수 없으며 변경할 수없는 20 개의 깊이있는 세트를 보았다. 그들 최근에.

캡슐화에 대해 걱정할 필요가 없습니다. 정말로. 마지막으로 복잡한 전자 상거래 사이트에서 jQuery의 핵심 요소를 다시 작성하거나 JQ 객체 메서드 및 기타 속성을 직접 변경하여 프론트 엔드 또는 UI 개발자가 직접 들었을 때, 모든 작업을 처리하지 않고 유용하게 사용할 수 있습니다. 다른 것들은 망가질 수 있겠습니까? 파이썬 아이들이 말하는 것처럼 "사용자를 신뢰하십시오". 비공개 인스턴스 변수는 인터페이스의 개념과 인터페이스의 개념을 명확히하는 데 도움이 될 수 있습니다. 그 유용성을 넘어, 모든 사람들이 언제나 우리 코드를 볼 수있는 마음과 인터넷에 두십시오.

JS에서 기능에 대해 할 수있는 모든 것을 배우십시오. 거기에는 JS OOP에서 유용 할 수있는 많은 것들이 있는데, 여기서 초점은 생성자보다 인스턴스에 더 많은 경향이 있습니다. 함수, 컨텍스트 및 호출/적용 메소드는 당신을 위해 적합한 구조를 고안하는 열쇠입니다.

+0

솔직히 말해, 지금까지는 객체 리터럴이 지금까지 충분했습니다. 나는 OO를 서버에두고 싶다. 그러나 나는 언어와 '최고의'관행을 이해하기를 정말로 원했습니다. 이 수업은 좋은 학습 도구로 보인다. – Phillip

+0

FYI 나는 귀하의 응답을 좋아했으며, 너무 많은 캡슐화와 상속을 피할 것입니다. 그러나 다른 응답은 질문에 더 가깝습니다. – Phillip

+0

나는 화나지 않았습니다. 나는 종종 잘 알려지지 않은 프로토 타입 속성을 도와주고 싶다. 나머지는 내 생각에 잠깐 멈춰서 물건에 대해 호언 장담했다. 더 큰 OOP 패러다임 (심지어 JS에서 많은 목적을 달성하지 못하는 패턴조차도 나에게 아이디어를 주었다.)에서 언어 컨텍스트에 대한 디자인 패턴을 읽고 두뇌에서 jQuery를 이해하는 것이 좋습니다. –

관련 문제