program/javascript

javascript oop

yoursyun 2008. 9. 17. 16:26

이 페이지는 어떻게 자바스크립트에서 클래스의 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 객체만을 남긴다.
반응형