Table of Contents

Prototype은 무엇인가.?

prototype.jsSam Stephenson에 의해 작성된 자바스크립트 라이브러리이다. 이 놀랍도록 멋진 생각과 표준에 의해 잘 작성된 코드의 일부는 웹2.0의 특성을 나타내는 풍부하고 상호작용하는 웹페이지와 많은 연관을 가진다.

만약 당신이 최근 이 라이브러리를 사용하기 시작했다면, 당신은 아마도 이 문서가 가장 좋은 지시사항중에 하나는 아니라는것을 알아차렸을것이다. 나 이전에 다른 많은 개발자들처럼, 나는 소스코드와 이것을 사용한 경험에서 prototype.js에 대한 지식을 가지게 되었다. 나는 모든 이가 배우고 공유하는 동안 좀더 많은 정보를 얻게 되는게 가장 좋은 것이라고 생각한다.

나는 objects, classes, functions, 그리고 이 라이브러리에 의해 제공되는 확장을 위한 비공식적인 참조문서 또한 제공한다.

당신이 예제와 참조문서를 읽었을때, Ruby프로그래밍 언어에 친숙한 개발자는 Ruby의 내장 클래스와 이 라이브러리에 의해 구현된 많은 확장 사이의 의도적인 유사성을 알아차리게 될것이다.

toc

관련글

고급 자바스크립트 가이드문서.

toc


toc

유틸리티 함수들(utility functions)

라이브러리는 미리 정의된 많은 수의 객체와 유틸리티 함수를 가진다. 이 알기쉬운 함수들의 목적은 반복적인 타이핑과 어구를 많이 줄이는데 있다.

toc

$() 함수 사용하기

$()함수는 가장 많이 사용되는 DOM의 document.getElementById()함수에 대한 편리한 단축키이다. DOM함수처럼, 이것은 인자로 던져진 id를 가진 요소를 하나 반환한다.

하지만 DOM함수와는 달리, 이것은 여러개의 id를 사용할수 있고 $()는 요청된 요소를 가진 Array객체를 반환할것이다. 예제는 아래와 같다.

<HTML>
<HEAD>
<TITLE> Test Page </TITLE>
<script src="prototype-1.4.0.js"></script>

<script>
function test1()
{
var d = $('myDiv');
alert(d.innerHTML);
}

function test2()
{
var divs = $('myDiv','myOtherDiv');
for(i=0; i<divs.length; i++)
{
alert(divs[i].innerHTML);
}
}
</script>
</HEAD>

<BODY>
<div id="myDiv">
<p>This is a paragraph</p>
</div>
<div id="myOtherDiv">
<p>This is another paragraph</p>
</div>

<input type="button" value=Test1 onclick="test1();"><br>
<input type="button" value=Test2 onclick="test2();"><br>

</BODY>
</HTML>

이 함수의 다른 좋은 점은 이것은 인자형태를 가질수 있는 다른 함수를 생성할때 매우 유용하도록 만들어주는 id문자열이나 요소객체 자체를 던질수 있다는 것이다.

toc

$F() 함수 사용하기

$F() 함수는 다른 단축키이다. 이것은 text박스나 드랍다운 list와 같은 어떤 필드의 입력 컨트롤의 값을 반환한다. 이 함수는 요소 id나 요소객체 자체를 인자로 가질수 있다.

<script>
function test3()
{
alert( $F('userName') );
}
</script>

<input type="text" id="userName" value="Joe Doe"><br>
<input type="button" value=Test3 onclick="test3();"><br>

toc

$A() 함수 사용하기

$A() 함수는 이것을 받아들이는 하나의 인자를 Array객체로 변환한다.

Array 클래스를 위한 확장과 조합된 이 함수는 이것을 더욱 쉽게 만든다. 예를 들면, 작성한 함수는 인자의 수를 유연하게 받아들인다.

<script>

function showOptions(){
var someNodeList = $('lstEmployees').getElementsByTagName('option');
var nodes = $A(someNodeList);

nodes.each(function(node){
alert(node.nodeName + ': ' + node.innerHTML);
});
}
</script>

<select id="lstEmployees" size="10" >
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Show the options" onclick="showOptions();" >

toc

$H() 함수 사용하기

$H() 함수는 결합된 배열을 열거할수 있는 Hash객체로 변환한다.

<script>
function testHash()
{
//let's create the object
var a = {
first: 10,
second: 20,
third: 30
};

//now transform it into a hash
var h = $H(a);
alert(h.toQueryString()); //displays: first=10&second=20&third=30
}

</script>

toc

$R() 함수 사용하기

$R() 함수는 new ObjectRange(lowerBound, upperBound, excludeBounds)를 작성하기 위한 짧은 형태이다.

이 클래스의 완전한 설명을 보기 위해 ObjectRange 클래스 문서를 보라. each 메소드를 통해 반복(iterators)의 사용법을 보여주는 간단한 예제를 보자. 더 많은 메소드는 Enumerable 클래스 문서에서 볼수 있을것이다.

<script>
function demoDollar_R(){
var range = $R(10, 20, false);
range.each(function(value, index){
alert(value);
});
}

</script>

<input type="button" value="Sample Count" onclick="demoDollar_R();" >

toc

Try.these() 함수 사용하기

이것은 인자처럼 많은 수의 함수를 가지고 그것들을 순서대로 차례차례 호출하도록 해준다. 이것은 함수중에 하나씩 수행하고 성공적인 함수호출의 결과를 반환할때까지 순차적으로 수행된다.

예제는 아래와 같다. xmlNode.text는 몇몇 브라우저에서 작동하고 xmlNode.textContent는 다른 브라우저에서 작동한다. Try.these()함수를 사용하면 당신은 작동하는 것중 하나를 반환할수 있다.

<script>
function getXmlNodeValue(xmlNode){
return Try.these(
function() {return xmlNode.text;},
function() {return xmlNode.textContent;}
);
}
</script>

toc

Ajax 객체

위에서 언급된 유틸리티 함수들은 좋다. 하지만 다시 보자. 그것들은 대부분 고급(advanced) 형태는 아니다. 당신은 스스로 이것들을 만들수 있고 당신 자신만의 스크립트에 유사한 함수를 이미 가지고 있을수도 있다. 하지만 이러한 함수들은 단지 일부분에 해당되는 팁일뿐이다.

나는 prototype.js에 대한 당신의 관심이 대부분의 AJAX기능을 다룰수 있다는 것이라고 확신한다. 그래서 당신이 AJAX로직을 수행할 필요가 있을때 좀더 쉽게 사용하도록 도와주는 라이브러리를 사용하는 방법을 살펴보자.

AJAX객체는 AJAX함수를 작성할 때 포함되는 트릭성격의 코드를 포장하고 단순화하기 위한 라이브러리에 의해 생성된 미리-정의된 객체이다. 이 객체는 캡슐화된 AJAX로직을 제공하는 많은 수의 클래스를 포함한다. 그 클래스중에 몇개를 살펴보자.

toc

Ajax.Request 클래스 사용하기

만약 당신이 어떠한 헬퍼(helper) 라이브러리도 사용하지 않는다면, 당신은 XMLHttpRequest객체를 생성하기 위한 많은 코드를 작성할 것이고 단계를 비동기적으로 수행할것이다. 그리고나서 응답을 뽑아내고 이것을 처리한다. 그리고나서는 한가지 이상의 브라우저를 지원하지 않는다면 스스로 행운이라고 생각할 것이다.

AJAX기능을 지원하기 위해, 라이브러리는 Ajax.Request클래스를 정의한다.

당신이 다음처럼 XML응답을 반환하는 http://yoursever/app/get_sales?empID=1234&year=1998 url을 통해 서버와 통신할수 있는 애플리케이션을 가지고 있다고 해보자.

<?xml version="1.0" encoding="utf-8" ?> 
<ajax-response>
<response type="object" id="productDetails">
<monthly-sales>
<employee-sales>
<employee-id>1234</employee-id>
<year-month>1998-01</year-month>
<sales>$8,115.36</sales>
</employee-sales>
<employee-sales>
<employee-id>1234</employee-id>
<year-month>1998-02</year-month>
<sales>$11,147.51</sales>
</employee-sales>
</monthly-sales>
</response>
</ajax-response>

XML을 가져오기 위해 서버와 통신하는 것은 Ajax.Request객체를 사용하면 매우 간단하다. 아래의 샘플은 이것을 수행하는 방법을 보여준다.

<script>
function searchSales()
{
var empID = $F('lstEmployees');
var y = $F('lstYears');
var url = 'http://yourserver/app/get_sales';
var pars = 'empID=' + empID + '&year=' + y;

var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: pars,
onComplete: showResponse
});

}

function showResponse(originalRequest)
{
//put returned XML in the textarea
$('result').value = originalRequest.responseText;
}
</script>

<select id="lstEmployees" size="10" onchange="searchSales()">
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>
<select id="lstYears" size="3" onchange="searchSales()">
<option selected="selected" value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
</select>
<br><textarea id=result cols=60 rows=10 ></textarea>

Ajax.Request객체의 생성자의 두번째 파라미터를 알아보겠는가.? {method: 'get', parameters: pars, onComplete: showResponse} 파라미터는 문자적 표기법으로 익명 객체를 나타낸다. 이것이 의미하는 것은 'get' 문자열을 포함하는 명명된 메소드(method)의 프라퍼티, HTTP요청 문자열을 포함하는 명명된 파라미터(parameter)의 프라퍼티, 그리고 함수 showResponse를 포함하는 onComplete 프라퍼티/메소드를 가지는 객체를 전달한다는 것이다.

당신이 AJAX를 비동기적으로(asynchronous) 서버에 호출할지를 결정하고 truefalse값으로 셋팅할수 있는 asynchronous(디폴트 값은 true이다.)와 같은 이 객체내 정의하고 활성화시킬수 있는 다른 프라퍼티가 몇개 있다.

이 파라미터는 AJAX호출을 위한 옵션을 정의한다. 샘플에서, 우리는 HTTP GET명령을 통해 첫번째 인자에서 url을 호출한다. 변수 pars내 포함된 조회문자열(querystring)을 전달하고 Ajax.Request객체는 응답을 받아들이는 작업을 마칠때 showResponse함수를 호출할 것이다.

당신이 아는것처럼, XMLHttpRequest는 HTTP호출을 하는 동안 진행과정을 보고한다. 이 진행과정은 4가지의 단계(Loading, Loaded, Interactive, 또는 Complete)를 알릴수 있다. 당신은 이러한 단계중에서 Ajax.Request객체 호출을 사용자정의 함수로 만들수 있다. Complete는 가장 공통적인 단계이다. 함수를 객체에게 알리기 위해, 우리 예제의 onComplete처럼 요청옵션내 onXXXXX로 명명된 프라퍼티/메소드를 간단히 제공하라. 당신이 전달하는 이 함수는 XMLHttpRequest객체 자체가 될 하나의 인자를 가진 객체에 의해 호출될것이다. 당신은 반환 데이터를 얻기 위해 이 객체를 사용할수 있고 아마도 호출의 HTTP결과 코드를 포함할 상태(status) 프라퍼티를 체크할것이다.

두개의 다른 흥미로운 옵션은 결과를 처리하기 위해 사용될수 있다. 우리는 AJAX호출이 에러없이 수행될때 호출될 함수처럼 onSuccess옵션을 명시할수 있다. onFailure옵션은 서버에러가 발생할때 호출될 함수가 될수 있다. onXXXXX의 선택적인 함수처럼, 이 두가지는 AJAX호출이 옮기는 XMLHttpRequest객체를 전달하도록 호출될수 있을것이다.

1.4.0 버전에서, 이벤트 콜랙 핸들링의 새로운 형태가 소개되었다. 만약 당신이 AJAX호출이 발생하는데도 불구하고 특정 이벤트를 위해 수행되어야 하는 코드를 가지고 있다면, 당신은 새로운 Ajax.Responders 객체를 사용할수 있다.

당신이 AJAX호출이 진행중이라는 시각적 표시를 보여주길 원한다고 해보자. 당신은 두개의 전역 이벤트 핸들러를 사용할수 있다. 하나는 첫번째 호출이 시작되었을때 아이콘을 보여주는것이고 다른 하나는 적어도 하나가 끝났을때 아이콘을 숨기는 것이다. 아래의 예제를 보자.

<script>
var myGlobalHandlers = {
onCreate: function(){
Element.show('systemWorking');
},

onComplete: function() {
if(Ajax.activeRequestCount == 0){
Element.hide('systemWorking');
}
}
};

Ajax.Responders.register(myGlobalHandlers);
</script>

<div id='systemWorking'><img src='spinner.gif'>Loading...</div>

우리의 샘플은 흥미로운 방법으로 XML응답을 처리하지는 않았다. 우리는 textarea내 XML을 집어넣었다. 응답의 전형적인 사용법은 XML내부에서 바라는 정보를 찾고자 할것이고 몇몇 페이지 요소나 페이지내 HTML을 만드는 몇가지의 XSLT변형을 업데이트할것이다.

좀더 완전한 설명을 보기 위해서, Ajax.Request 참조options 참조를 보라..

toc

Ajax.Updater 클래스 사용하기

만약 당신이 HTML로 이미 포맷팅된 정보를 반환할수 있는 서버 종료점(endpoint)을 가진다면, 라이브러리는 당신이 Ajax.Updater클래스를 사용하는것을 좀더 쉽게 만들어준다. 이것으로 당신은 어느 요소가 AJAX호출로부터 반환된 HTML을 채우는지 알리게 된다. 예제는 내가 글로 표현하는 것보다 당신을 좀더 쉽게 이해하도록 도와줄것이다.

<script>
function getHTML()
{
var url = 'http://yourserver/app/getSomeHTML';
var pars = 'someParameter=ABC';

var myAjax = new Ajax.Updater(
'placeholder',
url,
{
method: 'get',
parameters: pars
});

}
</script>

<input type=button value=GetHtml onclick="getHTML()">
<div id="placeholder"></div>

당신이 보는것처럼, 코드는 onComplete함수와 생성자에 전달된 요소 id를 제외하고 이전예제에 비해서 매우 간단하다. 클라이언트에서 서버 에러들을 다루는 것이 어떻게 가능한지 보기 위해 코드를 조금 변경해 보자.

우리는 호출을 위해 더 많은 옵션을 추가하고 에러 상황을 뽑아내기 위해 함수를 명시한다. 이것은 onFailure옵션을 사용하여 수행한다. 우리는 성공적인 작동의 경우에만 활성화될 묶음자(placeholder)를 명시할것이다. 이것을 달성하기 위해, 우리는 간단한 요소 id에서 두개의 프라퍼티(success-모든것이 정상적일때 사용되는, failure-어떤것이 실패일때 사용되는)를 가지는 객체로 첫번째 파라미터를 변경할 것이다. 우리는 예제에서 failure 프라퍼티를 사용하지 않을것이고, onFailure옵션에서 reportError함수를 사용할것이다.

<script>
function getHTML()
{
var url = 'http://yourserver/app/getSomeHTML';
var pars = 'someParameter=ABC';

var myAjax = new Ajax.Updater(
{success: 'placeholder'},
url,
{
method: 'get',
parameters: pars,
onFailure: reportError
});

}

function reportError(request)
{
alert('Sorry. There was an error.');
}
</script>

<input type=button value=GetHtml onclick="getHTML()">
<div id="placeholder"></div>

만약 당신의 서버 로직이 HTML마크업 대신에 자바스크립트 코드를 반환한다면, Ajax.Updater객체는 자바스크립트 코드가 될수 있다. 자바스크립트로 응답을 처리하기 위한 객체를 얻기 위해, 당신은 객체 생성자의 마지막 인자로 프라퍼티들의 목록에 evalScripts: true;를 간단히 추가한다. 하지만 여기엔 문제가 있다. 이러한 스크립트 블럭은 페이지의 스크립트에 추가되지 않을것이다. 옵션이름인 evalScripts이 제시하는것처럼, 스크립트는 평가될것이다. 차이점이 무엇일까.? 요청된 URL이 반환하는 것이 무엇인지 추측해보자.

<script language="javascript" type="text/javascript">
function sayHi(){
alert('Hi');
}
</script>

<input type=button value="Click Me" onclick="sayHi()">

이 경우 당신이 이전에 이것을 시도했다면 이것이 작동하지 않는것을 알고 있을것이다. 이유는 스크립트 블럭은 평가될것이고 평가된 스크립트는 sayHi 라는 이름의 함수를 생성하지 않을것이다. 이것은 아무것도 하지 않을것이다. 이 함수를 생성하기 위해, 우리는 함수를 생성하기 위해 변경할 필요가 있다. 아래를 보라.

<script language="javascript" type="text/javascript">
sayHi = function(){
alert('Hi');
};

</script>

<input type=button value="Click Me" onclick="sayHi()">

이전 예제에서, 우리는 변수를 선언하기 위해 var 키워드를 사용하지 않았다. 그렇게 하는 것은 스크립트 블럭에 지역화될 함수 객체를 생성할것이다. var 키워드 없이 함수 객체는 window범위에서 작동한다.

좀더 상세한 complete설명을 위해서는, Ajax.Request 참조문서Ajax.options 참조문서를 보라.

toc

열거(Enumerating)...

우리는 루프(loop)에 친숙하다. 당신이 알다시피, 배열 자체를 생성하고 같은 종류의 요소로 채운다. 루프 제어구조(이를 테면, foreach, while, repeat 등등)을 생성하고 숫자로 된 인덱스를 통해 순차적으로 각각의 요소에 접근하고 그 요소로 작업을 수행한다.

당신이 이것에 대해 생각할때, 언제나 당신은 코드에 배열을 가지고 루프내 배열을 사용할것이라는것을 의미한다. 이러한 반복을 다루기 위해 좀더 많은 기능을 가진 배열 객체가 있다면 좋지 않겠는가.? 그렇다. 많은 프로그래밍 언어는 배열이나 유사한 구조(collection과 list와 같은)에서 이러한 기능을 제공한다.

prototype.js는 우리에게 반복가능한 데이터를 다룰때 사용하도록 구현된 Enumerable 객체를 제공한다. prototype.js 라이브러리는 더 나아가 Enumerable의 모든 메소드로 Array 클래스를 확장한다

toc

루프, 루비-스타일

표준 자바스크립트에서, 당신이 배열의 요소를 순차적으로 표시하길 원한다면, 당신은 다음처럼 작성할수 있다.

<script>
function showList(){
var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Meg'];
for(i=0;i<simpsons.length;i++){
alert(simpsons[i]);
}

}

</script>

<input type="button" value="Show List" onclick="showList();" >

prototype.js를 사용하면, 다음과 같이 다시 작성할수 있다.

	function showList(){
var simpsons = ['Homer', 'Marge', 'Lisa', 'Bart', 'Meg'];
simpsons.each( function(familyMember){
alert(familyMember);
});

}

당신은 특이한 문법으로 별로 좋지않다고 생각할지도 모른다. 위 예제에서, 엉망으로 만드는 것은 아무것도 없다.

each 메소드에 대한 인자처럼 전달되는 이 함수는 보았는가.? iterator 함수처럼 이것을 참조해보자.

toc

스테로이드(steroids)에서 당신의 배열

위에서 언급된것처럼, 이것은 같은 프라퍼티와 메소드를 가지는 배열내 모든 요소를 위해 공통이다. 우리의 새로운 배열을 가지고 iterator함수의 장점을 가질수 있는 방법을 보자.

문법에 따르는 요소를 찾아라.

<script>
function findEmployeeById(emp_id){
var listBox = $('lstEmployees')
var options = listBox.getElementsByTagName('option');
options = $A(options);
var opt = options.find( function(employee){
return (employee.value == emp_id);
}
);
alert(opt.innerHTML); //displays the employee name
}
</script>

<select id="lstEmployees" size="10" >
<option value="5">Buchanan, Steven</option>
<option value="8">Callahan, Laura</option>
<option value="1">Davolio, Nancy</option>
</select>

<input type="button" value="Find Laura" onclick="findEmployeeById(8);" >

배열에서 항목을 걸러내는 방법을 보자. 그리고나서 각각의 요소로부터 맴버를 가져온다.

<script>
function showLocalLinks(paragraph){
paragraph = $(paragraph);
var links = $A(paragraph.getElementsByTagName('a'));
//find links that do not start with 'http'
var localLinks = links.findAll( function(link){
var start = link.href.substring(0,4);
return start !='http';
});
//now the link texts
var texts = localLinks.pluck('innerHTML');
//get them in a single string
var result = texts.inspect();
alert(result);
}

</script>
<p id="someText">
This <a href="http://othersite.com/page.html">text</a> has
a <a href="#localAnchor">lot</a> of
<a href="#otherAnchor">links</a>. Some are
<a href="http://wherever.com/page.html">external</a>
and some are <a href="#someAnchor">local</a>
</p>
<input type=button value="Find Local Links" onclick="showLocalLinks('someText')">

이것은 이 문법에 완전히 빠지도록 하기 위한 몇가지 예제를 가진다. 사용가능한 모든 함수를 위해 Enumerable and Array 참조문서를 보라.

toc

내가 강력하게 추천하는 책들.

다음의 책들은 AJAX애플리케이션을 만들기 위해 요구되는 새로운 스킬을 배우는데 많은 도움을 주었고 이미 알고 있던 스킬을 좀더 탄탄하게 만들어주었다. 나는 좋은 책이 충분히 금적적인 가치를 하고 오랜시간동안 가치를 이어간다고 생각한다.

+ Recent posts