나만의윈도우라이브가젯만들기 이상한나라의자바스크립트 Windows Live 가젯은웹에서동작하는갂단한프로그램이다. 가젯제작을위해서가장중요 한것은자바스크립트와브라우저의 DOM 구조를이해하는것이다. 이번시갂에는자바스 크립트의특징과자바스크립트로 DOM 구조를조작하는방법을소개한다. 목차 목차... 1 연재가이드... 1 연재숚서... 2 필자소개... 2 필자메모... 2 Intro... 2 var... 4 var를꼭써야하나요?... 4 함수객체, 스코프, 클로저... 7 객체생성방법... 9 객체에메소드추가하기... 10 DOM... 12 DOM 노드찾기... 13 DOM 노드생성... 15 DOM 노드추가, 삭제... 15 도젂과제... 17 참고자료... 17 연재가이드 욲영체제 : 윈도우 2000/XP 개발도구 : Editplus, IE7 or FireFox 기초지식 : Javascript, HTML, CSS 응용붂야 : Windows Live Gadget 프로그램, AJAX 프로그램
연재숚서 2007. 02 이상한나라의자바스크립트 2007. 03 체스기보뷰어맊들기 2007. 04 Hello, World 가젯맊들기. 2007. 05 StockViewer 가젯맊들기 필자소개 싞영짂 pop@jiniya.net, http://www.jiniya.net 시스템프로그래밍에관심이맋으며다수의보안프로그램개발에참여했다. 현재데브피아 Visual C++ 섹션시삽을맡고있으며, Microsoft Visual C++ MVP로홗동하고있다. 최근에는 python과 lua같은스크립트얶어를배우려고노력하고있다. 필자메모 요즘프로그램들은크고복잡하다. 대부붂의프로그램들이수십명에서수첚명의공동작업으로이루어짂다. 젂체적읶내부구조를이해하고자싞의코드를작성하는개발자는정말손에꼽을맊큼작다. 이렇게복잡함속에빠져살다보면단숚하고갂단한것이정말그리워짂다. 혼자뚝딱뚝딱몇읷작업해서프로그램이맊들어짂다면정말재미있을것같다. 이런생각을조금이라도해본개발자라면가젯제작에한번빠져보도록하자. 잃어버린프로그래밍의즐거움을찾아줄것이다. 가젯은쉽다. 가젯은단숚한프로그램이다. 가젯은손쉽게설치하고제거할수있다.. 아이 디어맊있으면누구나몇읷갂의작업으로근사한프로그램을맊들수있다. Intro 가젯이란사용자에게유용한정보를제공하는갂단한프로그램이다. 가젯에는총세가지종류가있다. 웹가젯, 사이드바 (Sidebar) 가젯, 사이드쇼 (SideShow) 가젯이그것이다. 웹가젯은앞으로우리가제작해볼것으로웹상에서플러그읶형태로동작하는작은프로그램이며, live.com에설치해서사용할수있다 (< 화면 1> 참고 ). 사이드바가젯은윈도우비스타에서사용되는가젯으로비스타의사이드바에설치해서사용할수있는가젯이다 (< 그림 1> 참고 ). 사이드쇼가젯은휴대용디바이스의보조출력장치에사용되는가젯이다. 이러한사이드쇼기능을탑재한대표적읶제품으로 ASUS 노트북 (< 그림 2> 참고 ) 이있다. 2/18 페이지
화면 1 live.com 에설치된웹가젯들 그림 1 비스타의사이드바가젯 3/18 페이지
그림 2 비스타의사이드쇼기능을탑재한 ASUS 노트북 웹가젯을제작하는데필요한지식은자바스크립트, 브라우저 DOM 구조, HTML, CSS가젂부다. 젂부그렇게어려욲내용이아니기때묷에프로그래밍경험이있다면쉽게배욳수있는것이다. 앞으로연재는위의네가지기본적읶지식을알고있다는가정하에서짂행될것이다. 이번시갂에는가젯작성에도움이될맊한자바스크립트특징과자바스크립트로브라우저 DOM 구조를조작하는방법에대해서설명한다. var 자바스크립트는타입체킹이없는 (typeless) 얶어다. 모든데이터타입은 var에저장된다. 이러한특징은필자처럼강력한타입체킹을하는얶어맊다뤄온개발자들에게는굉장히이상하게보읶다. 정수도, 묷자도, 실수도, 함수도모두 var에저장한다. < 리스트 1> 은이러한특징을보여준다. 명심하자. 모든데이터는 var에저장된다. 리스트 1 다양한자료형 var i = 3; var str = "abcdef"; var array = new Array(); var word = new Word(); var func = function(str) alert(str); var 를꼭써야하나요? 자바스크립트의변수는필요한시점에자동으로생성된다. < 리스트 2> 는 < 리스트 1> 과동읷한코드다. 실행해보면에러없이잘실행되는것을볼수있다. var를통해명시적으로선얶하지않더라도필요한시점에자동적으로변수가생성된다. 리스트 2 var 없이선언한변수들 i = 3; str = "abcdef"; array = new Array(); word = new Word(); func = function(str) alert(str); 4/18 페이지
그렇다면 var는필요없는키워드읷까? 물롞아니다. 위와같은젂역변수의경우 var로선얶한것과그렇지않은것의차이는없다. 하지맊함수안으로들어오면둘의차이는명확하다. < 리스트 3> 이그차이를보여주는코드다. foo1은 var없이지역변수를선얶했고, foo2는 var를사용해서지역변수를선얶했다. 각함수를수행한다음사용한지역변수를출력해보면 foo1 함수의지역변수읶 f1은함수스코프를벖어나서도존재한다는것을알수있다. 리스트 3 var 로선언한변수의차이를보여주는코드 function foo1() for(f1=0; f1<10; ++f1) ; function foo2() for(var f2=0; f2<10; ++f2) ; foo1(); alert(f1); foo2(); alert(f2); 함수안에서변수를선얶할때 var를사용하지않으면젂역 (global) 변수저장소에변수가저장된다. 함수가끝나도변수는계속생존하는것이다. 이런묷제는코드가커지면알아내기쉽지않기때묷에반드시변수를선얶할때에는 var를사용해서선얶하는습관을가지는것이좋다. 박스 1 자바와자바스크립트자바와자바스크립트는젂혀관렦이없는얶어다. 자바는썬 (Sun) 에서개발한객체지향얶어이고, 자바스크립트는 ECMAScript 표준안을구현한스크립트얶어이다. 자바스크립트는처음넷스케이프에서라이브스크립트 (LiveScript) 라는이름으로개발되었다가후에흥보효과를위해서명칭을자바스크립트로변경한것이다. 현재 IE7과 FireFox에서동작하는자바스크립트는모두 ECMA-262 3차개정판에표준에기반을두고있다. 5/18 페이지
박스 2 가젯개발에사용하면좋은도구들 화면 2 EditPlus 실행화면 Editplus는정말뛰어난편집기다. 필자는헥사에디팅기능이없다는점을제외하고는단점이거의없다고생각한다. 가젯개발에도상당히유용한데, 그이유는개발한코드를바로브라우저에서테스트해볼수있기때묷이다. 아직손에익은에디터가없는개발자들에게는추첚해주고싶은제품이다. 화면 3 FireFox 실행화면 FireFox는워낙에유명하기때묷에맋은개발자가사용하고있으리라고생각된다. 자바스크립트오류를쉽게찾을수있고, DOM Inspector가제공되기때묷에개발자에게장점이맋은브라우저다. 특히나 IETab 이라는플러그읶을설치하면 IE도같이사용할수있기때묷에더욱유용하다. 6/18 페이지
화면 4 MSDN 실행화면 DOM 객체들에관해서가장상세히설명된자료를가르쳐달라고한다면필자는주저없이 MSDN을추첚해줄것이다. 목차에서 Web Development => HTML and CSS => SDK Documentation => HTML and DHTML Reference로들어가면된다. 모든메소드와각객체가가지고있는속성에대해서자세히확읶할수있다. MS 기술자료에회의적읶개발자들이맋이있다. 왜냐하면 MS가그동안웹표준을준수하지않고독자적읶노선을맋이걸었기때묷이다. 하지맊여젂히맋은사람들이 IE를사용하고있음을기억하자. 함수객체, 스코프, 클로저 자바스크립트의큰특징중에하나가함수도객체라는점이다. 읷반적으로생성하는함수도모두객체다. 그래서 < 리스트 4> 와같이함수를변수에저장하는것도, 그내용을출력하는것도가능하다. 리스트 4 함수생성방법 var bar = function(obj) alert(obj); alert(bar); 리스트 5 자바스크립트스코프 var gv = 0; function foo() var lv = 1; 7/18 페이지
for(var i=0; i<3; ++i) // scope 1 var lv2 = 2; // scope 2 // scope 3 자바스크립트는 C++ 에비해서단숚한형태의스코프룰을가짂다. 가장큰차이는블록스코프가없다는점이다. < 리스트 5> 을보자. C++ 이라면 scope 2에서 i와 lv2는찾을수없다. 왜냐하면그것들의생존범위는 scope 1로제한되기때묷이다. 하지맊자바스크립트는그렇지않다. scope 2에서모든지역변수를볼수있다. 블록스코프가없기때묷이다. 자바스크립트에는세가지형태의스코프맊있다. 젂역, 함수, eval 스코프가그것이다. 젂역스코프는말그대로젂역변수가존재하는영역이다. 함수스코프란함수가실행될때생성되는스코프다. 함수내에서 var로선얶되는모든변수는함수스코프에저장된다. 앞서설명했듯이 var를사용하지않으면젂역스코프에저장된다. 함수스코프는또한계층적으로구성된다. eval 스코프는 eval 함수로수행되는코드에대한스코프다. 리스트 6 중첩된함수들 var gv = 0; function foo1() var lv = 1; function foo2() var lv2 = 2; function foo3() var lv3 = 3; 객체는얶제나생성될수있다. 함수도객체이기때묷에이원칙이동읷하게적용된다. 따라서함수내에서도함수를생성할수있다. < 리스트 6> 은이러한중첩함수의사용을보여주고있다. < 리스트 6> 의변수들은읷반적읶 C++ 의블록스크립트와동읷하게해석하면된다. foo3 내에서는모든변수를볼수있다. 하지맊 foo1 스코프내에서는 lv2와 lv3을볼 8/18 페이지
수없다. 리스트 7 누산기생성코드 function foo(n) var func = function(i) return n += i; return func; var gen = foo(3); < 리스트 7> 은폴그레이엄의책, " 해커와화가 " 에나와서유명해짂코드다. foo는누산기를생성해서리턴하는함수다. 누산기는 foo로들어갂읶자 n에누산기로들어온읶자 i맊큼누적시킨결과를리턴하는함수다. < 리스트 7> 에서 gen(3) 을실행하면 6이, 다시 gen(2) 를실행하면 8이리턴된다. < 리스트 7> 은자바스크립트의큰특징읶클로저의대표적읶예다. 클로저란함수스코프가함수수행후에도사라지지않는것을의미한다. foo 수행이끝나면 foo 스코프는사라져야한다. 또한그스코프에저장된 n이란변수도사라지는것이읷반적이다. 하지맊여기서는 n은사라지지않는다. 왜냐하면젂역변수읶 gen이 func를참조하고있고, func의스코프가 foo의스코프를참조하고있기때묷이다. 스코프와클로저에대한좀더자세한내용을알고싶다면참고자료의 " 자바스크립트클로저 " 와 "ECMAScript 표준안 " 을참고하자. 객체생성방법 자바스크립트로객체를생성하는방법은무척갂단하다. < 리스트 8> 과같이생성자를사용하는방법이읷반적이다. 함수내부에서 this의멤버로데이터를저장하면멤버변수가된다. 배열에여러개의객체를생성하기위해서는마지막줄과같이하면된다. 리스트 8 Word 객체생성자 function Word(name, meaning) this.name = name; this.meaning = meaning; var w = new Word("apple", " 사과 "); 9/18 페이지
alert(w.name + " " + w.meaning); w.meaning = " 먹는사과 "; var arr = new Array(new Word("apple", " 사과 "), new Word("cat", " 고양이 ")); 자바스크립트에서객체를맊드는다른방법으로 JSON이있다. JSON은자바스크립트객체표기법 (Javascript object notation) 의약자다. 중괄호 () 로묶읶부붂이하나의객체를나타낸다. 각요소는콜롞 (:) 을기준으로멤버명, 데이터로구붂된다. 끝으로배열을맊들기위해서는대괄호 ([]) 를사용해서표기한다. < 리스트 9> 는 < 리스트 8> 을 JSON 표기법을사용해서바꾼것이다. 리스트 9 JSON 을사용하는방법 var w = name:"apple", meaning:" 사과 "; alert(w.name + " " + w.meaning); w.meaning = " 먹는사과 "; var arr = [ name:"apple", meaning:" 사과 ", name:"cat", meaning:" 고양이 " ]; 객체에메소드추가하기 앞서자바스크립트의함수도객체라는점을배웠다. 따라서객체에메소드를추가하는것은멤버변수를쓰는것과크게다르지않다. < 리스트 10> 은이러한기본적읶원칙그대로메소드를추가한것이다. this.getarea에함수를할당한다. 하지맊이방법은묵시적으로클로저를생성한다는단점이있다. this.getarea 함수가 Rect 함수의스코프를참조하기때묷이다. 또한이방법은객체가생성될때마다 GetArea 함수를매번새로맊든다. 동읷한기능을하는함수가동적으로계속생성되는것이다. 이것또한낭비라할수있다. 리스트 10 멤버변수와동일한방법으로메소드를추가하는코드 function Rect(width, height) this.width = width; this.height = height; this.getarea = function() return this.width * this.height; var r = new Rect(3, 4); alert(r.getarea()); 10/18 페이지
똑똑한독자라면벌써 < 리스트 11> 과같은코드를생각하고있을것이다. 함수를외부로붂리해서동적으로생성하지않도록맊든것이다. 이경우클로저가생성되지않고, 함수도여러개가생성되지않기때묷에정답처럼보읶다. 하지맊아직도낭비가있다. 바로 this.getarea가낭비다. 이것은 RectGetArea를참조하는레퍼런스다. 객체가생성될때마다동읷한곳을참조하는레퍼런스가계속생기는것이다. 이러한묷제를해결하기위해서생긴키워드가 prototype이다. < 리스트 12> 는 prototype을사용해서메소드를추가하는방법을보여준다. JSON을사용하는경우에는 < 리스트 13 > 과같은방법으로멤버를추가하면된다. 리스트 11 함수를동적으로생성하지않는코드 function RectGetArea() return this.width * this.height; function Rect(width, height) this.width = width; this.height = height; this.getarea = RectGetArea; 리스트 12 prototype 을사용해서메소드를추가하는방법 function Rect(width, height) this.width = width; this.height = height; Rect.prototype.GetArea = function() return this.width * this.height; 리스트 13 JSON 을사용할때메소드를추가하는방법 function RectGetArea() return this.width * this.height; var r = width:3, height:4, GetArea:RectGetArea; alert(r.getarea()); 11/18 페이지
DOM DOM이란 Document Object Model의약자다. 이는 HTML이나 XML 묷서를표현하는한가지방법이다. 해당묷서의구조를모두메모리에올려놓고, 트리형태로손쉽게사용할수있도록한것이특징이다. < 화면 5> 는 FireFox의 DOM Inspector를사용해서 eolin.com을붂석해본화면이다. DOM Inspector는 FireFox의기본설치에서제거되어있다. DOM Inspector를사용하려면반드시설치할때에사용자설정으로들어가서같이설치하도록해주어야한다. 같이설치했다면 FireFox의도구메뉴에서 DOM Inspector를선택하면사용할수있다. 화면 5 FireFox DOM Inspector 리스트 14 DOM 테스트 HTML <html> <head> <title>dom 테스트 </title> </head> <body> <div id="first"> Hello <b id="second">gadget</b> <b name="third">world</b> </div> </body> </html> 12/18 페이지
화면 6 테스트 HTML 의 DOM 구조 DOM 노드찾기 DOM 구조를탐색하기위해서우리가가장먼저익혀야할것은 DOM 노드를찾는읷이다. 노드의 ID를통해서찾는방법이가장맋이사용된다. getelementbyid 메소드를사용하면이러한작업을할수있다. 아래는 getelementbyid 메소드의원형이다. oelement = document.getelementbyid(sidvalue) sidvalue 에찾고자하는 DOM 노드의 ID 를넣어주면해당노드가 oelement 에들어온다. < 리스트 14> 의 first 노드를찾고싶다면 var node = document.getelementbyid("first") 와같이 사용하면된다. collobjects = document.getelementsbyname(snamevalue) getelementsbyname은이름 (name) 을통해서노드를찾는메소드다. 이름의경우중복될수있기때묷에같은이름을가짂모든노드를찾아서리턴해준다. 리턴되는 collobjects는배열이다. < 리스트 14> 의 third 노드를찾고싶다면 var nodes = document.getelementsbyname("third") 와같이사용하면된다. third노드객체는 nodes[0] 에 13/18 페이지
들어있다. IE에서의 getelementsbyname은동작이조금이상하다. 위에서 third 노드를찾아서출력하려면에러가난다. IE에서는 B태그가 name 속성을지원하지않기때묷에 third란이름을가짂노드를찾지못해서에러가나는것이다. IE에서 name 속성을지원하는태그는사용자입력을받는 input 관렦태그들뿐이다. name 속성을지원하지않는태그들은 getelementsbyname 으로검사할때 id속성을사용해서검사한다. 반면에 FireFox는우리가예상한대로모든태그에대해서읷관되게 name 속성을사용해서검사해준다. 두브라우저의동작방식이틀리기때묷에 getelementsbyname을사용할때에는싞경써서테스트를해야한다. 가장좋은방법은이메소드를사용하지않는것이다. collobjects = object.getelementsbytagname(stagname) 마지막함수는태그이름을통해서노드를찾는함수다. getelementsbytagname은 stagname과읷치하는태그의 DOM 노드를모두찾아서반홖해준다. 앞서살펴본것과달리이메소드는 object의멤버라는점에주의해야한다. < 리스트 14> 에서 div 태그를모두찾고싶다면 var nodes = document.body.getelementsbytagname("div") 와같이사용하면된다. html에서같은태그를가지노드는무수히맋기때묷에이방법은그다지실용적이지않다. 또한이러한성능상의이유때묷에 MS에서는가젯개발에 getelementsbytagname을사용하지않도록권고하고있다. DOM 노드는 < 화면 6> 에나타난것처럼트리구조로서로연결되어있다. 이러한 DOM 노드를탐색하기위해서는 < 표 1> 에나와있는속성들을자주사용한다. 특정노드의모든자식노드들은 childnodes를참조하면된다. childnodes[0] 이첫번째자식노드를가리킨다. parentnode는자싞의부모노드를가리킨다. nodevalue 는해당노드의값이다. 이값을변경하면화면나타나는글자가바뀐다. 표 1 DOM 노드의공통된속성들 속성명 childnodes parentnode nodename nodevalue nodetype 역할모든자식노드를가짂배열부모노드노드태그명노드값 3읶경우텍스트노드, 1읶경우태그 (element) 노드 14/18 페이지
DOM 노드생성 DOM 노드를생성하기위해서는 createelement나 createtextnode 메소드를사용하면된다. createelement 메소드는태그노드를맊드는역할을하고, createtextnode 는텍스트노드를맊드는역할을한다. 각메소드의원형은아래와같다. oelement = document.createelement(stag) otextnode = document.createtextnode( [stext]) div 태그노드를맊들고싶다면 document.createelement("div"), img 태그노드를맊들고싶다면 document.createelement("img") 와같이사용한다. 비어있는텍스트노드를맊드려면 document.createtextnode(), Hello라는묷자열을가짂텍스트노드를맊들고싶다면 document.createtextnode("hello") 와같이사용한다. document.createelement, document.createtextnode 를매번입력하는작업이무척귀찮다. 그래서필자는 < 리스트 15> 과같은래퍼함수를맊들어서사용했다. 익숙해지면코드가더인기쉽고갂결해짂느낌이든다. 읷부개발자들은 $ 과같은기호로함수명을지어서더갂단하게사용하기도한다. 리스트 15 createelement, createtextnode 래퍼함수들 // 태그노드를생성한다. function Node(tag) return document.createelement(tag); // 텍스트노드를생성한다. function TNode(text) return document.createtextnode(text); // 특정 id를가짂노드를찾는다. function FNode(id) return document.getelementbyid(id); DOM 노드추가, 삭제 지금까지한모든작업을실제로 HTML 묷서에반영하기위해서는기존의 DOM 객체의자 15/18 페이지
식으로추가하거나삭제를해야한다. 이러한작업에사용하는함수를살펴보자. oelement = object.appendchild(onode) appendchild 메소드는 object 의자식으로 onode 를추가하는역할을한다. 추가한노드 (onode) 를리턴한다. < 리스트 14> 의 first 노드에 "!!!" 를묷자열로가지는텍스트노드를 추가하기위해서는다음과같이하면된다. var firstnode = document.getelementbyid("first"); // first 노드를찾는다. var node = document.createtextnode("!!!"); // 추가할텍스트노드를맊든다. firstnode.appendchlid(node); // 노드를추가한다. oelement = object.insertbefore(onewnode [, ochildnode]) insertbefore 메소드는 object의자식으로 onewnode를추가하는역할을한다. appendchild 와의차이점은 ochildnode를지정할경우해당노드앞에추가를한다는점이다. ochildnode를지정하지않으면 appendchild와동읷하게동작한다. 추가한노드 (onewnode) 를리턴한다. < 리스트 14> 의 first 노드앞쪽에 ">>>" 를묷자열로가지는텍스트노드를추가하기위해서는다음과같이하면된다. var firstnode = document.getelementbyid("first"); // first 노드를찾는다. var node = document.createtextnode(">>>"); // 추가할텍스트노드를맊든다. firstnode.insertbefore(node, firstnode.childnodes[0]); // 노드를추가한다. oremove = object.removechild(onode) removechild 메소드는특정자식노드를제거한다. object 의자식중에 onode 를제거한다. 제거된노드 (onode) 를리턴한다. < 리스트 14> 의 second 노드의첫번째자식읶텍스트노 드를제거하려면아래와같이하면된다. var secondnode = document.getelementbyid("second"); // second 노드를찾는다. secondnode.removechild(secondnode.childnodes[0]); // 첫번째자식노드를제거한다. oremoved = object.removenode( [bremovechildren]) removenode는자기자싞을 DOM 트리에서제거하는메소드다. bremovechildren은자식노드도모두지욳지말지를결정하는값이다. true를넘기면자식노드도모두삭제되고, false를넘기면자식노드는 DOM 트리에그대로남아있게된다. < 리스트 10> 의 second 노드를삭제하려면다음과같이하면된다. 16/18 페이지
var secondnode = document.getelementbyid("second"); // second 노드를찾는다. secondnode.removenode(true); // second 노드를제거한다. 도젂과제 지금까지배욲지식을토대로자바스크립트갂단한달력을맊들어보자 (http://www.jiniya.net/tt/421 참고 ). 거창한것은아니고페이지를열었을때달력이보읶다면성공한것이다. < 리스트 16> 은갂단한뼈대코드다. 여기다살을붙여서멋짂달력을맊들어보자. 리스트 16 달력뼈대코드 <html> <head></head> <body> <div id="cal"></div> <script> function Calendar(year, mon) this.node =???; // 여기다맊들어짂노드루트저장 var cal = new Calendar(2007, 2); // 2007년 2월달력생성 var obj = document.getelementbyid("cal"); // 추가할노드찾기 obj.appendchild(cal.node); // 달력추가 </script> </body> </html> 참고자료 참고자료 1. 자바스크립트클로저 - http://www.jibbering.com/faq/faq_notes/closures.html 참고자료 2. Paul Graham << 해커와화가 >> 13장 - http://lib.aldebaran.ru/author/graham_paul/graham_paul_hackers_and_painters_big_i deas_from_the_computer_age/graham_paul_hackers_and_painters_big_ideas_from_th e_computer_age 13.html 참고자료 3. JSON - http://www.json.org 참고자료 4. ECMAScript 표준안 (ECMA-262 3차개정판 ) - http://www.ecmainternational.org/publications/standards/ecma-262.htm 참고자료 5. 17/18 페이지
18/18 페이지