2009-01-07 7 views
18

생성자의 메소드와 프로토 타입 객체를 통해 설정하는 방법의 차이점에 대해 설명해 주시겠습니까? 다음 코드는 방법을 설정하는 두 가지 방법을 보여줍니다 - say_hellosay_bye은 모두 잘 작동 : 당신이 메시지 클래스에서 클래스를 파생 할 때프로토 타입 객체 또는 생성자를 통한 설정 방법, 차이점은 무엇입니까?

function MessageClass() { 
    this.say_bye = function() { alert('see ya'); }; 
} 

MessageClass.prototype.say_hello = function() { alert('hello'); }; 

x = new MessageClass(); 
x.say_hello(); 
x.say_bye(); 

답변

31

foxxtrot과 annakata는 모두 정확하지만 나는 2 센트를 던질 것입니다.

"MessageClass"의 각 인스턴스는 실제로 동일한 기능을 참조합니다. 함수는 메모리에 한 번만 존재하며 모든 인스턴스에 사용됩니다. 프로토 타입 대신 생성자에서 메서드를 선언하거나 (또는 ​​특정 인스턴스에 추가하는 경우) MessageClass의 각 인스턴스에 대해 새 함수가 만들어집니다.

즉, 대부분의 경우 눈에 띄는 성능 차이는 없으며 메모리 사용량 차이가 발생할 가능성은 거의 없습니다. 다른 방법을 강구 할만한 이유가 없다면 프로토 타입 방법으로 갈 것입니다. 내가 클로저가 필요한 경우 생성자에서 메서드를 선언하고 싶을 수있는 유일한 이유가 있습니다. 당신이 이벤트 핸들러가 있거나 게터/세터와 개인 특성을 시뮬레이션하고 싶었 예를 들어, 당신은 할 수 있습니다

function MessageClass() { 
    var self = this; 
    this.clickHander = function(e) { self.someoneClickedMe = true; }; 

    var _private = 0; 
    this.getPrivate = function() { return _private; }; 
    this.setPrivate = function(val) { _private = val; }; 
} 

편집 : 대한되고있다 때문에 토론을 어떻게 기능을 가진 다른 객체에 의해 확장이 효과를 객체 생성자에서 할당되었으므로 좀 더 자세히 설명하겠습니다. 토론을 단순화하기 위해 "클래스"라는 용어를 사용할 수도 있지만, js가 클래스를 지원하지 않는다는 점에 유의해야합니다 (좋은 OO 개발을 할 수 없다는 의미는 아닙니다). 또는이 문제를 논의하지 않을 것입니다.

대부분의 자바 스크립트 라이브러리는 기본 클래스와 하위 클래스의 생성자를 호출합니다. (예 : Prototype.js의 Object.extend) 이는 각각의 생성자에 할당 된 메소드가 결과 객체에서 사용 가능함을 의미합니다. 그러나 개체를 직접 확장하는 경우 예기치 않은 결과가 발생할 수 있습니다.

은 내가 MessageClass가 이상 걸릴하고 확장 할 경우

function ErrorMessageClass() {} 
ErrorMessageClass.prototype = new MessageClass(); 

errorMsg = new ErrorMessageClass(); 

그런 다음에서 errormsg가에 getPrivate 및 setPrivate 방법이있을 것이다, 그러나 당신이 기대하는 것처럼 그들은 작동하지 않을 수 있습니다. 이러한 함수는 할당 될 때 범위가 지정되었으므로 (예 : "ErrorMessageClass.prototype = new MessageClass()"get/setPrivate 메서드가 공유 될뿐만 아니라 _private 변수도 ErrorMessageClass의 모든 인스턴스에서 공유됩니다. ErrorMessageClass의 static property입니다.경우 clickHandler 기능과 someoneClickedMe 속성과 마찬가지로

var errorA = new ErrorMessageClass(); 
var errorB = new ErrorMessageClass(); 
errorA.setPrivate('A'); 
console.log(errorA.getPrivate()); // prints 'A' 
console.log(errorB.getPrivate()); // prints 'A' 
errorB.setPrivate('B'); 
console.log(errorA.getPrivate()); // prints 'B' 

: 예 그러나

errorA.clickHandler(); 
console.log(errorA.someoneClickedMe); // prints 'true' 
console.log(errorB.someoneClickedMe); // prints 'true' 

변경 해당 함수 정의 this._private를 사용하려면

this.getPrivate = function() { return this._private; }; 
this.setPrivate = function(val) { this._private = val; }; 

및 인스턴스의 동작을 ErrorMessageClass는 예상보다 더 많이됩니다.

errorA.setPrivate('A'); 
errorB.setPrivate('B'); 
console.log(errorA.getPrivate()); // prints 'A' 
console.log(errorB.getPrivate()); // prints 'B' 
+0

당신의 웅변을 위해 빌어 먹을 :) (비록 눈에 띄는 차이가 없다고 동의한다) – annakata

+0

this._private를 사용하면 외부에서 변수에 액세스 할 수 있지만. – Chris

+0

(기술적으로 말하면 대부분의 JS 환경에서 디버거를 사용하여 추적 할 수 있습니다) – Chris

5

의 차이입니다. 프로토 타입에서 선언 된 메소드 만 Message의 하위 클래스에서 사용할 수 있습니다.

+0

그래서 'BetterMessageClass.prototype = new MessageClass'만 'say_hello'만 상속됩니까? – snitko

+0

자식 클래스에서 "say_bye"메서드 ("this"로 선언 됨)를 호출 할 수 있습니다. 내 코드는 다음과 같습니다. function Employee() { this.say_bye = function() {alert ('ya'참조); }; } function 관리자() { } Manager.prototype = new Employee; Manager.prototype.constructor = Manager; var manager = 새 관리자(); manager.say_bye(); – Raghav

+1

@foxxtrot 맞지 않습니다. 'this'에서 생성자 내부에 선언 된 메소드조차도 하위 클래스에서 액세스 할 수 있습니다. Prestaul에 의해'errorA.setPrivate ('A')'코드를 생각해 보자. Prestaul은 부모 클래스'MessageClass'에 의해'this'에 선언 된 메소드에 접근한다. – Suneel

6

프로토 타입 JS로 메소드를 바인딩하는 경우 한 번만 수행하면됩니다. 그러면 객체 클래스에 바인딩됩니다 (OO JS 확장에 대해 알 수 있음).

"class"함수 내에서 바인딩을 수행하는 경우 JS는 모든 인스턴스에 대해 만들고 할당하는 작업을 수행해야합니다.

+0

성능 문제입니까? –

+0

예, 가장 확실하게 – annakata

+0

메소드를 funcation으로 먼저 정의한 다음 생성자에서 다음을 말합니다. 'this.say_bye = MessageClass_sayhello; – snitko