이 글은 오래된 전에 작성된 글입니다. 따라서 최신 버전의 기술에 알맞지 않거나 오류를 유발할 수 있습니다.
저자는 이 글에 대한 질문을 받지 않을 것입니다. 하지만 이 글이 리뉴얼 되면 이 글에 대한 질문을 하거나
토론을 할 수도 있습니다.
웹 프로그래밍을 처음 배우는 사람에게 당황스러운 것 중 하나가 바로 HTML 스크립트일 것입니다. 기껏
ASP.NET으로 구조화된 프로그래밍을 해 왔는데, 그것만으로 웹 어플리케이션을 작성한다는 것이 어림 반푼어치도 없는
일임은 아는 사람들은 다 알지요... 항상 브라우저 측의 UI를 개선하기 위해 HTML 스크립트, 좀 더 구체적으로 말해서
자바 스크립트를 사용하지 않을 수 없습니다. 그러다 보니 자연스레 자바 스크립트를 사용하게 되는데...
이번 포스트에서는 자바 스크립트를 다룰 때 유용하지만 많은 개발자가 잘 모르는 기법 하나를 소개하고자 합니다. 저의
비장의 꽁수인데... 한 동안 포스트를 올리지 못한 죄책감에 몇 마디 적어 봅니다.
Java Script Tip : Interception
지랄 같은 자바 스크립트는 자바와 비슷하게 생겨먹었지만 자바와는 그 근본부터가 다른 이상한(?) 녀석이기 때문에 닷넷스러운 접근을 했다가는 우스운 꼴 당하기 십상이다. 자바 스크립트를 배우려고 할 때 또 한가지 당황스러운 점은 이
녀석에 대한 책을 찾기도 어렵다는 것이다. 대부분 자바 스크립트를 3류 프로그래밍으로 여기기 때문에 이에 관련된 책을 저술하는
것을 꺼리기 때문이라고 생각한다. 인터넷을 잘 뒤져 보면 스크립트에 대한 강좌를 찾을 수도 있겠지만 대부분 잘 정리된 것이
아니라 간략한 팁들이 주종을 이룬다.
그렇다고 쑛도 모르는 필자가 자바 스크립트 강좌를 한다는 것은 아니고, 대다수의 개발자가 잘 모르지만
알아두면 아주 유용하게 써먹을 수 있는 팁을 하나 소개하고자 한다.
Inside Java Script Function
인터셉션, 우리나라 말로 하자면 가로채기 정도 되겠다. 가끔씩 내가 작성한 코드가 아닌 ASP.NET 런타임에 의해
생성된 자바 스크립트 함수의 행동을 바꾸고 싶은 경우가 있다. 필자의 경우에는 커스텀 Validation 컨트롤을 작성할
때 ASP.NET 런타임이 생성하는 클라이언트 측 유효성 확인 자바 스크립트 함수에 필자의 코드를 삽입 시키고 싶었던 적이
있었다. 이러한 상황이 발생하면 큰 어려움 없이 이미 존재하는 자바 스크립트 함수의 행동을 바꾸어 버릴 수 있다.
아놔... 그냥 소스를 수정해 버리지 왜 가로채기 따위를 해야 하냐고? 소스를 수정한다는 얘기는 ASP.NET
런타임이 제공하는 .js 파일을 수정한다는 말이 되겠지? 만약에 패치나 기타 등등의 이유로 .js 가
덮어쓰기(overwrite) 된다면 어떻게 될까? 당연히 새로이 덮어 쓰여지는 파일에 내가 했던 그 수정을 다시 해주어야
하는 엿 같은 상황이 발생할 수도 있다.
또 한가지 소스를 직접 수정하는데 부담은 대개의 ASP.NET 런타임은 여러 웹 어플리케이션에 의해 공유된다는
점이다. 서버에 내 웹 어플리케이션만 독야청청 한다면 밀려오는 귀차니즘에 .js를 쏠랑 바꿀 법도 하지만, 여러 웹
어플리케이션이 오순도순 살고 있는 서버라면 대략 뷁스런 상황이 발생할 수 있음은 구구절절이 설명하지 않아도 알 것이다.
마지막으로 소스를 직접 수정하기 어려운 점은, ASP.NET 2.0에 포함된 웹 리소스(Web Resource)란
기능으로 DLL 내에 .js, .css, 이미지 파일들을 포함시켜놓고 WebResource.axd 를 이용하여 DLL 내의
리소스를 웹 컨텐트인양 사용하기 때문에 원천적으로 소스 수정이 곤란할 수도 있다.
그래서 내가 왔잖아 !
그래서 기존 자바 스크립트 함수의 행동을 바꾸는 방법을 필자가 소개하고자 한다. 정확히 말하면 기존 함수의 내용을
바꾸는 것이 아니라 기존 함수를 통채로 들어 내고 새로운 함수를 끼워 넣는 것을 말한다.
이 방법을 이해하기 위해서는 기본적으로 HTML 내의 자바 스크립트가 갖는 사상을 이해해야 한다. 자바 스크립트에서
function 이란 키워드는 다양한 용도로 사용되며 자바 스크립트 함수는 그 차제로서 객체로 간주된다는 점이 핵심
포인트이다. 함수가 객체로 간주된다는 말은 new 키워드를 통해 새로운 함수를 만들 수도 있다는 말도 된다. 잘 이해가 안
간다면 다음 스크립트 코드를 째려봐 보자.
1 <script
type="text/javascript"
language="javascript">
2 function
foo()
3 {
4
alert("foo");
5 }
6
7 var
myfunction = foo;
8
9 myfunction();
10 </script>
리스트1. 간단한 자바 스크립트 함수 제어
리스트1에서 일단 간단한 함수 foo를 정의한다. 이것까지는
아~조~(매우) 평범하다. 그런데 100% (10%는 1할이라고 하죠. 100%는?)... 변수에다가 함수를 할당하는 것은 무엇인가?
즉, var myfunction = foo 란 수식이 무엇을 의미하는 것인가?
이것을 이해 하려면 앞서 필자가 말한 자바 스크립트의 함수가 객체로 간주된다는 말을 기억해야 한다. foo 란 이름은
함수 객체에 대한 참조(reference)를 가지고 있는 변수일 뿐이다. 좀더 정확히 말하면 foo 란 이름은 window
객체의 속성으로 정의되어 있다. 즉, 다음 두 문장은 완전히 동일한 것으로 위 문장은 window 객체의 표현을 생략해
놓은 것이다. HTML 자바 스크립트에서 window 객체는 생략이 가능하지 않은가?
var myfunction = foo;
// 다음 두 라인은 같다.
var myfunction = window.foo;
HTML 자바 스크립트에서 글로벌 변수와 글로벌 함수는 모두 window 객체의 속성으로 정의됨을 기억해 두면 두고
두고 유용하다.
리스트1에서 9 번째 라인을 잘 째려 보자. 웬 변수에 괄호를 붙였을까?
자바 스크립트에서 괄호의 의미는 함수 호출이 되겠다. myfunction 이란 변수가 함수 객체를
참조(reference)하고 있다면 그 함수가 호출될 것이다. myfunction 변수에 foo 함수 참조를 할당해
놓았으므로 9 번째 라인은 foo 함수를 호출하게 되는 것이다. 재밌지 않은가?
결론적으로 리스트1 코드의 결과는 foo 라는 함수를 호출하는 코드이다.
리스트1은 C/C++ 에서나 볼 수 있는 함수 포인터와 매우 유사한 개념으로
접근하면 매우 쉽게 이해될 수 있을 것이다. C/C++을 모른다고? 쩝 그럼 할말은 없고... -_-;
동적으로 함수를 만들어 보장
자바 스크립트에서도 동적으로 함수를 만들 수 있다. 구구절절이 설명하면 귀찮으니 바로 코드를 보자.
1 <script
type="text/javascript"
language="javascript">
2 var
dynamic_func = new Function("param1",
"alert(param1)");
3 dynamic_func("hello
dynamic function");
4 window.dynamic_func("again
!!!");
5 </script>
리스트2. 동적 함수 생성 및 테스트
리스트2의 2 번째 라인이 바로 동적으로 함수를 생성하는 코드이다. new 키워드와 더불어 Function 객체를
생성하는 것을 볼 수 있을 것이다. 필자가 말했던 "자바 스크립트에서 함수는 객체로 간주된다"는 말이 구라가 아님을
적나라하게 보여주는 코드인 것이다. 생성된 함수 객체를 변수에 할당하고 그 변수 뒤에 괄호를 붙여주면 함수 호출이 일어남은
이미 리스트1에서 보였다.
Function 객체를 생성할 때 사용하는 자바 스크립트 문법은 다음과 같다.
functionName
= new Function( [argname1, [... argnameN,]]
body );
new 의 생성자(?) 매개변수 중 마지막 매개변수가 생성하고자 하는 함수의 바디(body)이며 그 앞에 붙는 것들은
모두 매개변수의 이름으로 간주됨에 유의하자. 구체적인 예제들은 다음과 같다.
var func1 =
new Function("alert('this is body');");
// 매개변수 없음
var func2 =
new Function("x", "y", "alert('this is body')"); //
매개변수 x, y 정의
var func3 =
new Function("a", "b", "c", "alert('this is body')");
// 매개변수 a, b, c 정의
Intercepting Function
자바 스크립트 함수에 대한 참조를 얻어낼 수 있음을 리스트1에서 보였고,
동적으로 함수를 생성하는 방법도 리스트2를 통해 배웠다. 이젠 이미 정의되어
있는 함수를 가로채어 나의 루틴이 수행되게 하는 것은 매우 쉬운 작업이 되어 버린다.
이젠 감 잡아쓰~
내가 소스에 대해 제어를 할 수 없는 .js 파일에 이미 정의되어 있는 자바 스크립트 함수 SomeFunc 가 있다고
가정해 보자. 그리고 HTML 내에서 SomeFunc 함수를 여러 번 호출하는 상황에서 이 함수의 행동을 바꾸고자 한다면
앞서 설명한 내용을 충분히 응용할 수 있다.
// somefile.js
1 function SomeFunc()
// 이 함수에 대한 생성을 내가 제어할 수 없다고 가정
2 {
3
alert("SomeFunc...");
4 }
//
somehtml.htm
1 <input
id="Test"
type="button"
onclick="SomeFunc();"
value="테스트"
/>
2
3 <script
type="text/javascript"
language="javascript">
4 var
orgFunc = SomeFunc;
5 SomeFunc
= new Function("alert('가로채기
: 선처리'); orgFunc();");
6 </script>
리스트3. 함수 가로 채기 예제
리스트3의 1 번째 라인의 <input> 태그에서 클릭 시 SomeFunc
함수를 호출함에 유의하자. 이런 상황에서 SomeFunc 수행 전에 어떤 작업을 해야 한다고 가정해보자.
somefile.js를 내가 수정할 수 있다면 아무런 문제가 없겠지만 그렇지 않은 상황이라면 어떻게 하겠는가? 이
경우 바로 3-6 라인의 스크립트 코드가 해결책이 된다. 4 번째 라인에서 원본 함수의 참조를 기록해 놓고 5 번째
라인처럼 새로운 함수를 생성하여 SomeFunc 에 할당해 버린다. 물론 새로운 함수는
전처리(pre-processing)을 한 후에 기억해 둔 원본 함수를 호출해 주어야만 할 것이다.
자... 이제 감을 잡았는가? 이런 방식으로 자바 스크립트 함수를 가로챌 수 있게 되는 것이다.
닭이 아니라면 응용해 보잣 !
응용이라 함은 별 것이 없고, 단순히 자바 스크립트 함수가 아닌 이벤트도 가로챌 수 있다는 것이다.
HTML 태그에 기록하는 이벤트 핸들러는 소위 말하는 익명
함수(anonymous function)이므로 이 함수도 동일하게 가로챌 수 있다. 뭐 가로챈다는
표현을 쓰기에도 좀 뭐하지만... 다음과 같은 코드로 기존 이벤트의 행동을 바꿀 수 있다는 말이다.
1 <input
id="Test"
type="button"
onclick="SomeFunc();"
value="테스트"
/>
2
3 <script
type="text/javascript"
language="javascript">
4 var
orgHandler = document.all["Test"].onclick;
5 document.all["Test"].onclick
= new Function("alert('가로채기
: 전처리'); orgHandler();");
6 </script>
리스트4. 이벤트 가로 채기
원리는 간단하다. 이벤트라는 것이 HTML 태그 요소(element) 객체의 속성처럼 액세스할 수 있기 때문에 가능한
것이다. 리스트4의 4 번째 라인은 원본 이벤트 핸들러를 변수에 기록해 두는 것이고 5 번째 라인은 새로운 이벤트 핸들러
함수를 onclick 에 할당하는 것이다. 이렇게 함으로써 이벤트 역시 가로채기가 가능하게 된다.
Conclusion
그렇다면 이런 팁을 언제 써먹을 수 있을까? 이런 것까지 필자에게 기대하면 좀 곤란하다. 자바 스크립트 함수를
가로채야 할 경우는 종종 발생하곤 한다. 내가 작성하지 않은 자바 스크립트,
즉 내가 소스를 수정할 수 없는 자바 스크립트, 이벤트 핸들러의 기본 행동을 바꾸고자 할 때 유용한
방법이므로 기억해 두면 좋을 듯 해서 글을 써 봤다.
이 팁을 구체적으로 사용하는 예제는 다음 기회에 글을 써 보겠다. 글이 너무 길어진 감이 있어서... 쩝...
Comments (read-only)
#일빠~~~~~따~~ / 땡초 / 11/25/2006 2:59:00 PM
요즘 atals 에 포함된 js 파일이나 샘플 등등 보면
정말 알수 없을 정도로 복잡하더군요...
이제 좀 이해가 가니 다시한번 훓어봐야겟어요
감사합니다^^//
#re: 스크립트 가지고 놀기 / 어흥이 / 11/26/2006 6:06:00 PM
좋은 글 감사합니다.
#re: 스크립트 가지고 놀기 / 다그닥 / 11/27/2006 9:24:00 AM
자바스크립을 하려면 좋은 레퍼런스가 필수 인데...
많은 분들이 알고 있으리라 보는데...
혹시나 해서 참고할 사이트 알려드립니다...
즐프 하세요... www.koxo.com
이 사이트 정리 하신분의 장인 정신이 놀랍습니다...^^
#re: 스크립트 가지고 놀기 / 이방은 / 11/27/2006 10:26:00 AM
저의 경우에는 통채로...재정의(?) 해서 쓰는데..
리소스로 된 js파일을 건들수 없기에 페이지에 똑같은 이름의 스크립트 메서드를 만들면..페이지에 있는 스크립트 메서드가 실행되죠..(맞는건가..@.@)
그래서 이런 조금은 아햏햏한 방법을 쓰긴 합니다만..
이런 내용도 있었군요..
역시 스크립트는 너무나..난해 합니다..@.@
좋은 글 감사합니다 ㅋ
근데 궁금한게..
외국아그들 예문 보면 foo 라는 말을 자주 쓰던데..이게 곰돌이 푸인가요?? 아님 뭔가 심오한 뜻이 있는 단어 조합의 initial인가요...
#re: 스크립트 가지고 놀기 / 블로그쥔장 / 11/27/2006 10:56:00 AM
다그닥// 레퍼런스 정리는 MSDN에도 되어 있고, 님께서 추천하신 사이트와 같이 정리되어 있는 곳은 있습니다만
그것을 어떻게 사용하고 응용하는 가에 대한 자료는 찾기 쉽지 않다는 것이지요.
그래서 우리 개발자들은 try & error 방식으로 노하우를 얻곤 한다는... T_T
이방은//
foo, bar 같은 함수 이름을 많이 쓰는데... 제가 학부 다닐 때 교수님께서 하신 말씀으로는
"프로그램 작성하다 보면 한숨(foo)이 많이 나오는데... 그러다 보면 바(bar)에 가서 술마신다고..."
이 말이 진짜인지 모르겠지만... 외국 프로그래머들 사이에서 예제로서 임의의 함수, 변수 이름으로
foo, bar 등의 이름을 많이 사용합니다. 일종의 관습 같은 걸로 저는 알고 있습니다만...
#2탄도 기대합니다. / 강희기 / 11/27/2006 1:51:00 PM
function을 그냥 클래스로 생각하고 코딩해보면 별 상관 없는거 같던데.. 좀 특이한 부분들이 있더군요
.prototype관련해서 재미난 부분이 많은것 같더라구요
특히 객체에 attatchEvent 할때는 좀 특이한 현상도 있던데.. 2탄 기대할께용..
#re: 스크립트 가지고 놀기 / 즈믄 / 12/2/2006 8:38:00 PM
오~~ 신기해요.. 이렇게도 쓸스 있는걸 전혀 몰랐습니다.
워낙 미천한 지식인지라...
재미있는 사실 하나 알았습니다.. 쥔장님 감사합니다...
2탄도 준비하신다니... 다시 기대하겠습니다... ^^
#re: 스크립트 가지고 놀기 / 참고 링크 / 5/11/2007 3:52:00 AM
#re: 스크립트 가지고 놀기 / 현양 / 7/11/2007 3:17:00 PM
<script>
var func = ci;
function ci(val){
return function(){
val++;
return val;
}
}
alert(func());
</script>
보면 익명 함수가.. alert 에서 문자열로 나와 버립니다. 무슨 .. 문제가 잇는건지..
아직.. 익명함수가 많이 어렵네요.. ㅡㅜ 여기서의 익명 함수의 기능도 설명 부탁드립니다..
#re: 스크립트 가지고 놀기 / 블로그쥔장 / 7/12/2007 2:44:00 AM
어찌되었건 보여주신 코드는 매우... 난해합니다. 이런 식의 코드는 좀 곤란하지요...
누가 봐도 이해하기 힘든 가독성이 크게 떨어지는 코드입니다.
코드는 보기 좋고 이해하기 좋은 것이 최고입니다. 제가 이 글을 쓴 이유는 일종의 팁일 뿐
코드를 보기 어렵게 작성하라는 의미는 아니였습니다.
위 코드에서 원하는 기능이 정확히 무엇인지 모르겠습니다만...
return 문장이 반환하는 것이 함수객체라면 new Function(...) 문장을 쓰셔야 합니다.
C#의 익명 메쏘드 처럼 사용하시면 좀 곤란하다는... 단순히 문자열이 반환되어 버리는 것이
어느 정도는 당연해 보입니다만...
사실 자바스크립트는 익명 메쏘드라는 개념이 없습니다만... 대신 함수를 객체로서 다룰 뿐입니다.
C#의 익명 메쏘드와 혼동하지 않으시길...
#re: 스크립트 가지고 놀기 / patrick / 12/10/2009 3:11:00 PM
태오 사이트에서 건너와서 읽고 갑니다...
이거 머리가 나빠서인지...예제 3번부터 확 헷갈리는 군요...--;;
그냥 외워놓고 다음에 다시한번 봐야 겠네요...^^