javascript

객체지향적 고급 자바스크립트 개발을 위한 가이드

jeeyong 2007. 12. 14. 16:04

Quick guide to somewhat advanced JavaScript

tour of some OO features

by Sergio Pereira
last update: February 21st 2006

Hey, I didn't know you could do that

여러분이 개발자이고 나와 같은 길을 걸어 왔다면, 웹페이지에서 꽤 많은 Javascript 조각들을 사용해 왔을 것이다. 마치 UI의 딱풀 마냥..

최근까지 나는 Javascript가 내가 취업 했을 때보다 더 객체지향(OO_ 능력을 가졌다고는 하지만 난 별로 그것을 사용해야하는 느낌은 받지 못했다. 브라우져들이 Javascript와 DOM의 좀더 표준화된 형상을 지원하기 시작함에 따라, client 상에서 구동하기 위한 더 복잡하고 기능적인 코드를 작성하 것이 가능해졌다. 그것은 AJAX 사상(事象)을 탄생하도록 도왔다.

우리 모두가 AJAX 애플리케이션을 만들기위해 코드를 작성하는 것을 것을 배울 즈음해서, 우리가 알고있었던 Javascript는 정말 빙산의 일각에 불과했다. 자, 이제 우리는 입력값 검사와 하찮은 업무들과 같은 간단한 UI 허드렛일들을 넘어서 사용되고 있는 Javascript을 살펴 볼 것이다. 요즘, client 상의 코드는 점점 더 진보적이고 계층화되며, 더 많이 실제 데스크탑 애플리케이션 또는 c/s환경의 무거운 client 처럼 되어 가고 있다. 우리는 class library, object model, hierarchy, pattern 들 그리고 단지 우리의 server 쪽 코드에서 눈에 익었던 다른 많은 것들을 알아 볼 것이다.

여러가지면에서 우리는 갑작스레 화면의 bar를 전보다 훨씬 높게 놓는것에 대해 얘기 할수 있다. 새로운 WEB을 위해 애플리케이션들을 작성하기 위해서는 훨씬 강도높은 기술의 숙달을 필요로 한다. 그리고 우리는 이 목적을 이루기 위해서 우리 자신의 Javascript 기술들을 향상시켜야만 한다. 만일 외부에 존재하는 많은 javascript library를 사용하기를 시도한다면, Prototype.js, Scriptaculous, moo.fx, Behaviour, YUI, 등등 처럼, 여러분은 결국 그 JS code를 여러분 스스로 판독해서 알아야 할것이다. 아마 여러분은 라이브러리들이 그것을 구현하는 방법을 배우기 원하거나 알기 원하거나 해서, 또는 라이브러리가 사용법을 이해하기 위한 유일한 방법이거나 해서, 문서가 대부분의 라이브러리들과 관련되어 있어 보이지 않거나 해서..( Maybe because you want to learn how they do it, or because you're curious, or more often because that's the only way to figure out how to use it, since documentation does not seem to be highly regarded with most of these libraries. 아마도 이유인즉 그것들이 어떻게 동작하지 배우고 싶기 때문이거나, 호기심 때문이거나, 종종 이 라이브러리들의 대부분이 문서화가 덜 되어있기 때문에, 사용법을 알기 위한 유일한 방법이 그것밖에 없기 때문일 것이다. ) 그 밖에 무엇이든지 그 경우에 있어서, 전에 그것과 같은 어떠한 것들을 본적이 없다면 여러분은 낯설고 두려운 상황에 직면하게 될 것이다.

이 글의 목적은 아직 익숙하지 않은 생성자들의 타입들을 꼼꼼히 설명함에 있다.

Related article

Prototype.js documentation

JSON

JavaScript Object Notation (JSON,)은 AJAX 테마와 관련하여 갑자기 뜬 새로운 기술 용어 중 하나이다. JSON은 javascript에서 선언적 object의 하나의 방식이다. 이제 바로 예제를 보고 어떻게 처리하는지 보도록 하자

var myPet = { color: 'black', leg_count: 4, communicate: function(repeatCount){
for(i=0;i<repeatCount;i++) alert('Woof!');} };

자, 소스 포맷을 약간 추가 해서 알아 보기 쉽게 보도록 하자:

var myPet = {
color: 'black',
legCount: 4,
communicate: function(repeatCount){
for(i=0;i<repeatCount;i++)
alert('Woof!');
}
};

여기서 우리는 두개의 속성들(colorlegCount)과 메서드(communicate)를 이용하여 object 참조를 만들었다. 콤마로 구분된 리스트로서 object의 속성들과 메소드들을 정의되어있는것을 이해하는것은 어렵지 않은 일이다. 각 구성들을 name으로 정의되어 보여지며 colon(:) 따라오서 그 다음으로 정의부 이다. 속성의 경우에서는 단지 값으로 정의부를 채운다. 익명 함수(anonymous function)을 할당으로 메소드들을 만든다. 이는 다음 아래 줄에서 더 자세히 설명할 것이다. object를 만든 후에 myPet 변수에 할당하며, 우리는 다음과 같이 이 변수를 사용 할수 있다:

alert('my pet is ' + myPet.color);
alert('my pet has ' + myPet.legCount + ' legs');
//if you are a dog, bark three times:
myPet.communicate(3);

여러분은 요즘 JS에서 도처에 사용되어진 JSON을 볼 것이다. 함수들에 인수, 리턴 값들, 서버의 응답들(string들 에서) etc.

What do you mean? A function is an object too?

이는 위 질문에 대해 생각해 본적 없는 개발자들에게는 좀 생소 할 것이지만 JS에서 함수(function) 또한 object이다. 예를 들어, string을 처리하는 다른 함수에 인자로서 함수를 처리 할 수 있다. 이는 광범위하게 사용되어지고 매우 유용하다.

이 예제를 보도록 하자. 우리는 다른 함수(annoyThePet)에 함수들(myDog.bark, myCat.meow)을 인자로 주어 줄 것이다. annoyThePet function에서 인자로 주어진 function을 사용 할 것이다.

var myDog = {
bark: function(){
alert('Woof!');
}
};

var myCat = {
meow: function(){
alert('I am a lazy cat. I will not meow for you.');
}
};

function annoyThePet(petFunction){
//let's see what the pet can do
petFunction();
}

//annoy the dog:
annoyThePet(myDog.bark);
//annoy the cat:
annoyThePet(myCat.meow);

우리가 myDog.bark 과 myCat.meow에 추가도니 괄호 "()" 없이 인자로 사용한 것에 대하여 주목 해야 한다. 만일 우리가 인수로 넘긴 function이 존재 하지 않거나 method를 호출하고 return value를 인수로 넘긴다면, 두 경우에 대해 undefined를 보일 것이다.

여러분이 나의 게으른 고양이가 개 처럼 짖게 만들기 원한다면, 여러분은 이처럼 쉽게 할 수 있다:

myCat.meow = myDog.bark;
myCat.meow(); //alerts 'Woof!'

Arrays, items, and object members

다음 JS안에 두 줄은 같은 일을 한다.

var a = new Array();
var b = [];

나는 여러분이 이미 알고 있는 대로, 여러분은 사각 괄호를 사용하여 array안의 각각의 아이템들을 접근 할 수 있다:

var a = ['first', 'second', 'third'];
var v1 = a[0];
var v2 = a[1];
var v3 = a[2];

하지만 여러분들을 숫자 색인으로만 접근 제한하지 않는다. 여러분은 string으로 멤버의 이름을 사용하여 JS object 각 멤버들을 접근 할 수 있다. 다음 예제는 빈 object를 만들고 name으로서 어떤 멤버들을 추가한다.

var obj = {}; //new, empty object
obj['member_1'] = 'this is the member value';
obj['flag_2'] = false;
obj['some_function'] = function(){ /* do something */};

위의 코드는 아래와 같이 동일한 효과를 가진다:

var obj = {
member_1:'this is the member value',
flag_2: false,
some_function: function(){ /* do something */}
};

다양한 방법으로, JS에서 object들의 사상과 연관 arraray(hashes)들은 구별 하지 않는다. 다음 두 줄 역시 같은 일을 한다.

obj.some_function();
obj['some_function']();

Enough about objects, may I have a class now?

OOP 프로그래밍 언어들의 강력한 힘은 class들의 사용에서 나온다. JS에서 나는 어떻게 class들을 정의하는지 나의 이전 경험으로 비춰볼때 짐작초차 하기 어렵다. 직접 판단하시오.

//defining a new class called Pet
var Pet = function(petName, age){
this.name = petName;
this.age = age;
};

//let's create an object of the Pet class
var famousDog = new Pet('Santa\'s Little Helper', 15);
alert('This pet is called ' + famousDog.name);

우리의 Pet class에 method를 추가 하는 방법을 보도록 하자. 우리는 모든 class들이 가지고 있는 prototype property를 사용하게 될 것이다. prototype property는 class의 어떠한 object가 가지고 있을 모든 멤버들을 포함하는 object이다. String, Number, and Date 같은 default JS class들 조차도 prototype object을 가지고 있다. 우리는 method들과 property들을 prototype object에 추가 할 수 있다. 그 class의 어떠한 object가 이 새로운 멤버를 자동으로 얻는다.

Pet.prototype.communicate = function(){
alert('I do not know what I should say, but my name is ' + this.name);
};

prototype.js과 같은 라이브러리는 여러모로 편리할 때가 있다. 만일 우리가 prototype.js를 사용한다면, 우리의 코드를 깔끔하게 할 수 있다.(적어도 내 견해로는..)

var Pet = Class.create();
Pet.prototype = {
//our 'constructor'
initialize: function(petName, age){
this.name = petName;
this.age = age;
},

communicate: function(){
alert('I do not know what I should say, but my name is ' + this.name);
}
};

Functions as arguments, an interesting pattern

만일 여러분이 클로져(절차를 오브젝트로서 취급하는 기능. 이 오브젝트화 된 절차를 클로져라함)를 지원하는 언어들 - Ruby 또는 C#2.0- 을 이용하여 작업한 적이 없다면 여러분은 다음 이디엄이 매우 생소하다는것을 느낄 것이다.

var myArray = ['first', 'second', 'third'];
myArray.each( function(item, index){
alert('The item in the position #' + index + ' is:' + item);
});

워~! 내가 너무 앞어서 여러분이 이것보다 더 좋은 기사를 찾아 보기 전에 여기 무슨 일이 생겼는지 설명한다.

무엇보다 먼저, 위 예제에서 우리는 prototype.js library를 사용하고 있다. 이것은 Array class에 each function을 추가한다. each function은 function object을 하나의 인자를 받는다. 차례로, array에서 각 item에 대해 이 function을 한번씩 호출 할 것이며, 호출될때 두개의 인자를 전달한다. 현재 item에 대한 그 item과 index 이다. 자 우리의 iterator function을 호출 해보자. 또한 우리는 이것과 같은 작성된 코드를 작성할 수 있다.

function myIterator(item, index){
alert('The item in the position #' + index + ' is:' + item);
}

var myArray = ['first', 'second', 'third'];
myArray.each( myIterator );

비록, 이 마지막 포맷이 이해하기에 더 편하지만 myIterator function을 찾는 코드에서 주변으로 튀어 버리는 현상을 야기한다. myIterator를 호출하는 같은 장소에서 iterator function의 로직을 가지는것이 좋다. 또한, 이경우에, 우리의 코드에서 어디 다른 곳에 iterator function를 필요로 하지 않을 것이며, 그래서 우리는 문제없이 myIterator function을 anonymous function로 할 수 있다.

원래의 예제를 더 분명하게 하기 위해서 어떤 하이라이팅 효과를 이용해서 다시 보자.

				
var myArray = ['first', 'second', 'third'];
myArray.each( function(item, index){
alert('The item in the position #' + index + ' is:' + item);
}
);

This is this but sometimes this is also that

우리가 가지고 있는 가장 일반적인 문제들 가운데 하나는 JS를 이용함에 있어서 this 키워드의 사용을 우리의 코드에 작성하기 시작할 때 이다. 그것은 실제 올가미가 될수 있다.

우리가 전에 언급한 것 처럼, 함수 또한 JS에서 object이고 때때로 우리는 function를 전달한 것을 알아 채지 못한다.

예제로 이 코드 조각으로 다뤄 보자.

function buttonClicked(){
alert('button ' + this.id + ' was clicked');
}

var myButton = document.getElementById('someButtonID');
var myButton2 = document.getElementById('someOtherButtonID');
myButton.onclick = buttonClicked;
myButton2.onclick = buttonClicked;

buttonClicked function를 어떠한 object 외부에서 정의 하였기 때문에 우리는 this 키워드가 window 또는 document object 참조를 포함 할 것이라고 생각하는 경향이 있을 것이다.(이코드 브라우저에서 보여지는 HTML 페이지의 중앙에 있다고 가정 하자.)

그러나 우리가 이 코드를 실행시켜 보면 그것이 클릭된 버튼의 id를 가리키거나 보여지는 것으로 작동되어 보여진다. 각 버튼의 onclick method은 buttonClicked object 참조를 포함하게 되며, 이전의 거기에 무엇이 있던간에 교체되어 진다. 버튼을 클릭할때 마다, 브라우저는 다음 줄과 같은 어떤 일을 수행할 것이다.

myButton.onclick();

결국 그렇게 혼란스러운것은 아니다. 그렇죠? 그러나 여러분이 다뤄야할 다른 object를 갖기 시작했고 버튼의 click과 같은 이벤트에서 이러한 object를 반응시키기 원한다.

var myHelper = {

formFields: [ ],

emptyAllFields: function(){
for(i=0; i<this.formFields.length; i++){
var elementID = this.formFields[i];
var field = document.getElementById(elementID);
field.value = '';
}
}
};

//tell which form fields we want to work with
myHelper.formFields.push('txtName');
myHelper.formFields.push('txtEmail');
myHelper.formFields.push('txtAddress');

//clearing the text boxes:
myHelper.emptyAllFields();

var clearButton = document.getElementById('btnClear');
clearButton.onclick = myHelper.emptyAllFields;

나의 페이지에서 Clear button을 클릭 할수 있고 이 3개의 text 박스들을 모두 비울 것이다. 그 다음에 여러분은 runtime error를 얻기 위해 단지 버튼 클릭만 시도하면 된다. 이 에러는 this 키워드와 관련 있을 것이다(추측 컨데..). 이 문제는 this가 버튼에 참조를 포함한다면 this.formFields가 정의 되지 않는다 것이다. 이것은 정확하게 무슨 일이 발생 하겠는가 이다. 한가지 빠른 해결책은 우리의 코드 마지막 줄을 재 작성하는 것이 될 것이다.

clearButton.onclick = function(){ myHelper.emptyAllFields(); };

그것은 우리가 helper object의 컨텍스트 안에 우리의 helper method를 호출하는 특정의 타입의 새로운 function을 만드는 방법이다.

'javascript' 카테고리의 다른 글

javascript에서 중복되지 않는 난수 만들기  (0) 2008.08.20
자바스크립트 정규식  (1) 2008.06.18
쿠키 보안  (0) 2007.12.06
자바스크립트 정규표현식  (4) 2007.11.28
자바스크립트 성능 향상 팁  (0) 2007.11.23