yoursyun
javascript oop 본문
이 페이지는 어떻게 자바스크립트에서 클래스의 private 변수와 메소드를 생성하는지 person이라는 간단한 예제를 통하여 보여줍니다. Part 2 는 상속을 다루겠습니다.
요약
- private 변수는 객체 안에서 'var' 키워드로 선언된다, 그리고 private 함수와 privileged 메소드만이 접근 할수 있다.
- private 함수는 객체의 생성자 안에서 선언된다. (또는 다른 방법으로
varfunctionName=function(){...}
이와 같은 방법을 통해 선언이 가능하다) 그리고 privileged 메소드에 의해서만 호출이 가능하다. (객체의 생성자를 포함해서). - privileged 메소드는 다음과 같이 선언한다.
this.methodName=function(){...}
객체 바깥의 코드로 호출이 가능하다. - public 속성은 다음과 같이 선언한다.
this.variableName
객체 바깥에서 읽기와 쓰기가 가능하다. - public 메소드는 다음과 같이 정의된다.
Classname.prototype.methodName = function(){...}
그리고 객체의 바깥으로부터 호출될수 있다. - prototype 속성은 다음과 같이 정의된다.
Classname.prototype.propertyName = someValue
- static 속성은 다음과 같이 정의된다.
Classname.propertyName = someValue
예
예제에서, 사람의 이름(name)과 인종(race)은 태어날때(birth) 값이 정해지며 절대 바뀌지 않는다. person 객체가 생성시에 그 person 객체는 1살의 나이로 시작되며 감춰진 수명(나이)이 정해진다. person 객체는 몸무게(weight)를 가지며 이 값은 먹는행위(eating)(3배의 몸무게 상승)와 운동(exercising)(몸무게 절반 감소)에 의해 변경된다. 매번 먹는행위와 운동하는 행위는 1살 더 나이를 먹게된다. 사람객체는 누구나 수정가능한 clothing 속성을 가지고 있다. 뿐만아니라 dirtyFactor도 수동적으로(더러운것이 묻는다거나 씻는행위) 값을 변경할수 있다. 그러나 dirtyFactor변수는 먹는행위와 운동을 할 때마다 증가하고 shower() 메소드를 사용함으로써 줄일수 있습니다.
예제코드
function Person(n,race){
this.constructor.population++;
// ************************************************************************
// PRIVATE 변수와 함수
// PRIVELEGED 메소드만 보기,수정,호출이 가능하다.
// ***********************************************************************
var alive=true, age=1;
var maxAge=70+Math.round(Math.random()*15)+Math.round(Math.random()*15);
function makeOlder(){ return alive = (++age <= maxAge) }
var myName=n?n:"John Doe";
var weight=1;
// ************************************************************************
// PRIVILEGED 메소드
// 어디서든 호출할수 있고 PRIVATE ITEMS에 접근이 가능하다
// PUBLIC FLAVORS와 함께 변경될수 있다
// ************************************************************************
this.toString=this.getName=function(){ return myName }
this.eat=function(){
if (makeOlder()){
this.dirtFactor++;
return weight*=3;
} else alert(myName+" 는 먹을수 없습니다, 그는 죽었습니다!");
}
this.exercise=function(){
if (makeOlder()){
this.dirtFactor++;
return weight/=2;
} else alert(myName+" 는 운동할수 없습니다, 그는 죽었습니다!");
}
this.weigh=function(){ return weight }
this.getRace=function(){ return race }
this.getAge=function(){ return age }
this.muchTimePasses=function(){ age+=50; this.dirtFactor=10; }
// ************************************************************************
// PUBLIC 속성 -- 누구든 읽고 쓸수 있다
// ************************************************************************
this.clothing="아무것도입지않음";
this.dirtFactor=0;
}
// ************************************************************************
// PUBLIC 메소드 -- 누구든 읽고 쓸수 있다
// ************************************************************************
Person.prototype.beCool = function(){ this.clothing="검은 셔츠" }
Person.prototype.shower = function(){ this.dirtFactor=2 }
Person.prototype.showLegs = function(){ alert(this+" 는 다리가 "+this.legs+" 개 입니다") }
Person.prototype.amputate = function(){ this.legs-- }
// ************************************************************************
// PROTOTYOPE 속성 -- 누구든 읽고 쓸수 있다 (overridden 할수 없습니다)
// ************************************************************************
Person.prototype.legs=2;
// ************************************************************************
// STATIC 속성 -- 누구든 읽고 쓸수 있다
// ************************************************************************
Person.population = 0;
// Person 클래스를 사용한 코드
function RunGavinsLife(){
var gk=new Person("Gavin","caucasian"); // Person 객체의 인스턴스를 생성
var lk=new Person("Lisa","caucasian"); // Person 객체의 인스턴스를 생성
alert("현재 "+Person.population+" 명의 사람이 있습니다");
gk.showLegs(); lk.showLegs(); // 'this.legs'를 참조할때 모두 'Person.prototype.legs' 변수를 공유한다
gk.race = "hispanic"; // 값을 변경하려고 해도 private 'race' 변수는 overwrite 되지 않는다.
alert(gk+"'의 인종은 "+gk.getRace()+" 입니다"); // 인스턴스 생성시에 지정된 private 'race' 변수로부터 'caucasian'을 리턴한다
gk.eat(); gk.eat(); gk.eat(); // 몸무게는 3... 9... 27
alert(gk+" 는 "+gk.weigh()+" 파운드의 무게가 나가며 dirt factor 는 "+gk.dirtFactor + "입니다");
gk.exercise(); // 몸무게 13.5
gk.beCool(); // 옷이 새로운 것으로 변경됩니다.
gk.clothing="Pimp Outfit"; // clothing 은 public 변수고 다른 값으로 변경이 가능합니다.
gk.shower();
alert("현재의 샤워기술로 "+gk+" 의 dirt factor가 "+gk.dirtFactor + " 이 되었습니다");
gk.muchTimePasses(); //50년이 지남
Person.prototype.shower=function(){ //모두에게 샤워 기술이 향상됨
this.dirtFactor=0;
}
gk.beCool=function(){ //Gavin 은 혼자서 새로운 패션 아이디어를 얻었다.
this.clothing="꽃남방";
};
gk.beCool(); gk.shower();
alert("패셔너블한 "+gk+" 는 "
+gk.getAge()+" 살이고 지금 "
+gk.clothing+" 를 입고있으며 dirt factor 는 "
+gk.dirtFactor+"이다");
gk.amputate(); //prototype 메소드를 사용하여 public 속성을 만듭니다
gk.showLegs(); lk.showLegs(); //Lisa는 여전히 prototype 속성을 가지고 있다
gk.muchTimePasses(); //50년이 지나고... Gavin 은 현재 100살이 넘었다.
gk.eat(); // 나이가 수명을 초과하였고 죽었기 때문에 먹을수 없다.
}
메모
maxAge
는 privileged accessor 메소드가 없는 private 변수이다; 그렇기때문에 이 값을 가져오거나 설정할수 있는 방법이 없다.race
는 생성자의 인자로 정의된 private 변수이다. 생성자에게 넘어간 변수는 객체에서 private 변수로서 사용가능하다.- '꽃남방' 을 입는
beCool()
메소드는gk
객체에만 적용된다, 전체의Person
클래서에 적용되지 않는다. 생성된 다른 사람객체들의beCool()
메소드는 여전히 원래의 '검은 셔츠' 옷을 사용하고 있고, Gavin 은 삶에서 그 옷을 입지 않는다. - 문자열 값을 사용하고자 할때
gk.toString()
를 호출하면 된다. 아래의 코드도 허용된다alert(gk+' is so cool.')
'Gavin'이라는 단어를 나타낸다, 그리고 이것은alert(gk.toString()+' is so cool.') 과 같다
. 자바스크립트에서 모든 타입의 각각의 객체는.toString()
메소드를 가지고 있다, 그러나 당신의 소유로 그것을 override 할수 있다. - (내가 아는한)객체의 생성자안에서 클래스의 public 메소드를 할당할수 없다..., 위에서
beCool()
와shower()
메소드 처럼 외부에선 반드시prototype
속성을 사용해야한다 Person.prototype.legs
속성과amputate()
함수, prototype 속성은 모든 객체 인스턴스에 의해 공유된다.lk.legs
를 질의하면 single prototype 속성을 보고 '2'를 대답한다. 그러나, 이값을 변경 하려고gk.legs=1
또는 (Person object에서)this.legs=1
둘중 하나의 방법을 사용하여 시도하는 것은 객체의 인스턴스에 완전히 새로운 public 속성을 만드는 것이다. (이것이gk.amputate()
는 Gavin의 다리만을 제거할뿐, Lisa에게는 적용되지 않는 이유다.) prototype 속성을 수정하기 위해서는,Person.prototype.legs=1
를 사용하거나this.constructor.prototype.legs=1
과 같은 방법을 사용해야한다. (내가 '~과 같은'이라고 말한 이유는this.constructor
가 객체의 private 함수안에서 사용할수 없는 것을 발견했기 때문이다, 여기서this
는window 객체를 참조한다.)- 어디서든 이름이 없는 함수의 선언은 인라인으로 다음과 같이 선언되어진다
foo = function(p1,p2){ some code }
new Function()
생성자는 같지 않다, 예를 들어.foo = new Function('p1','p2','code');
전역영역에서 후에 실행된 것은--생성자의 지역을 상속받는 대신에--그러므로 이것은 private 변수로 접근하는 것을 막아준다.(이 부분은 번역, 의역의 어려움이 있어서 일단 되는대로 직역했습니다. 해석이 틀릴수 있습니다 - 해석자 주) - 위의 코드에서 말한대로
gk.race
에 어떠한 값을 설정하는 행위로 private 변수인race
는 덮어쓰여지지 않는다. private 와 public 변수 두개를 같은 이름으로 가질수 있다. 예를 들면, 아래의 클래스의yell()
메소드는foo
와this.foo
을 각각 다른 변수 값을 나타낼 것이다 :function StupidClass(){
var foo = "internal";
this.foo = "external";
this.yell=function(){ alert("Internal foo is "+foo+"\nExternal foo is "+this.foo) }
} - Private 함수와 privileged 메소드, private 변수와 public 속성, 매번 새로운 객체가 만들어질때 인스턴스되어진다. 그렇기 때문에 매번
new Person()
이 호출되면,makeOlder()
,toString()
,getName()
,eat()
,exercise()
,weigh()
,getRace()
,getAge()
, 과muchTimePasses()
의 새로운 복사본이 생성된다. 모든 Person에게, 매번. 대조적으로 public 메소드는 (beCool()
과shower()
는 Person 객체가 얼마나 많이 생성되었던에 상관없이 오직 한번만 복사된다) 객체의 보호(객체의 변수값 조작을 막는 보안정도)를 포기하고 public 메소드만을 사용하는 것이 메모리/성능을 위한 이유로 선호될수 있다는 것을 알수 있다.
private 변수를 public 으로 만드는 것은 (privileged accessor 메소드없이는 그것들을 사용할 방법이 없다.) public 메소드는 그것들을 가질수 있고 또한 외부코드가 이 변수를 보거나 파괴하는 것을 허용하기 때문에 요구되어진다는 사실을 알아두어라. public 속성과 메소드만을 가지고 메모리/성능 최적화를 하는 것은 당신의 코드를 약하게 만드는 결과를 야기한다.
예를 들면, 위의age
와maxAge
는 private 변수다;age
오직 외부의getAge()
를 통해서만 접근이 가능하다 (값을 설정하는 것은 불가능하다) 그리고maxAge
는 바깥에서 읽거나 값을 설정할수 없다. 이 값을 public 속성으로 바꿈으로써 어느 코드에서든지gk.maxAge=1; gk.age=200;
다음과 같은 방법을 허용한다. 그러나 그것은 가능하지도 않고 이치에 맞지 않는다 (너는 누군가의 나이 또는 수명을 직접 조작할수가 없다), 그러나 이 값들을 설정함으로써 직접alive
변수는 업데이트 되지 않는다, 단지 상태가 깨진 Person 객체만을 남긴다.
반응형