Programmer/Javascript - 해당되는 글 3건
1. 단지 $ 축약형 하나만을 위해 Java Script Framework인 prototype.js(이하 프로토타입) 를
 쓸것인가....
  럭셔리한 Java Script Action을 위해 프로토타입 사용을 고민한 사람들이 있을것이다...
 이 소스는 약 200키로바이트로 얼마 안되어 보이지만 웹 브라우저와 클라이언트의 측면에서는
 대단히 무거운 소스이다.
   아래는 이 프레임웍에서 자주 사용되는 소스를 활용한 효과적인 팁중 하나이다.
 
  var $ = function(element) {
      return document.getElementById(elemelt);
  }
  위 소스는 프로토타입에서 단순히 $변수명 입력시에 객체를 리턴하기 위한 일부 기능을 소스로
  표현한 것이다 이 기능을 사용하기 위해서 위 소스를 직접 구현하여 사용하여도 된다.
    또는 아래와 같은 소스도 유용하다
  var $ = document.getElmentById;

2. innerHTML을 위해 길게 늘어쓴 String 연산
   Ajax또는 비동기 페이지를 위해 아래와 같은 소스를 사용한 경험들이 있을 것이다.

   var strHTML = "<div id='abcd'>";
   strHTML += "태그들";
   strHTML += "태그들";
   strHTML += "태그들";
   .....
   strHTML += "</div>";

   하지만 위 코드는 치명적인 단점이 있다(특히 IE에서) 왜냐하면 IE를 대표적으로 브라우저에서
  스트링 연산이 빠르지 않아 클라이언트의 부하가 늘수 있다는 것이다.
   아래는 이를 대처하기 위한 방법이다.
  var strHTML = new Array();
   strHTML.push(" 태그들 ");
   strHTML.push(" 태그들 ");
   strHTML.push(" 태그들 ");
   .....
   retrun strHTML.join("");

   위는 배열을 사용하여 배열에 추가하고 총합하여 리턴해주는 방식이다. 이 방식이 상위의
  스트링 연산의 방식보다 속도측면에서 개선할 수 있다고 한다.

3. Document 모델 보다는 DOM 형식의 ID로 찾기
   처음 또는 초보 개발자들은 document.(Form 이름).(컨트롤 이름).(속성) = "값"; 이런 방식으로
  구현해본 경험이 있을것이다.. 이는 W3C 표준에서는 document.getElementByID("ID 명").속성
  = "값"
과 같은 형태로 사용하기를 권장하고 있다.

4. Pseudo code 사용의 자제
   아래와 같은 코드를 대부분 사용해 본적이 있을 것이다.
   <a href ="javascript:goTo();">여기로 이동</a>
  
   위 사항 보다는 아래와 같은 방식을 추천한다.
 
   <a href="#" onclick="goTo();">여기로 이동</a>  또는
    <a href = "anyURL" onclick = "goTo();return false;">여기로 이동</a>
  
   이유는 코드 가독성 및 표준개발 가이드에 입각한 내용이라고 한다.

- 위 내용은 Daum Communication 구경택님의 자료를 바탕으로 했으며 저작권은 http://no7do.tistory.com/ 의 블로거 김도영과 구경택님에게 있음-


|

웹 프로그래밍을 처음 배우는 사람에게 당황스러운 것 중 하나가 바로 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

그렇다면 이런 팁을 언제 써먹을 수 있을까? 이런 것까지 필자에게 기대하면 좀 곤란하다. 자바 스크립트 함수를 가로채야 할 경우는 종종 발생하곤 한다. 내가 작성하지 않은 자바 스크립트, 즉 내가 소스를 수정할 수 없는 자바 스크립트, 이벤트 핸들러의 기본 행동을 바꾸고자 할 때 유용한 방법이므로 기억해 두면 좋을 듯 해서 글을 써 봤다.

이 팁을 구체적으로 사용하는 예제는 다음 기회에 글을 써 보겠다. 글이 너무 길어진 감이 있어서... 쩝...

경고 : 이 글을 무단으로 복제/스크랩하여 타 게시판, 블로그(개인 블로그 포함)에 게시하는 것은 허용하지 않습니다.


|
function roundTable(objID) {
      var obj = document.getElementById(objID);
      var Parent, objTmp, Table, TBody, TR, TD;
      var bdcolor, bgcolor, Space;
      var trIDX, tdIDX, MAX;
      var styleWidth, styleHeight;

      // get parent node
      Parent = obj.parentNode;
      objTmp = document.createElement('SPAN');
      Parent.insertBefore(objTmp, obj);
      Parent.removeChild(obj);

      // get attribute
      bdcolor = obj.getAttribute('rborder');
      bgcolor = obj.getAttribute('rbgcolor');
      radius = parseInt(obj.getAttribute('radius'));
      if (radius == null || radius < 1) radius = 1;
      else if (radius > 6) radius = 6;

      MAX = radius * 2 + 1;
     
      /*
              create table {{
      */
      Table = document.createElement('TABLE');
      TBody = document.createElement('TBODY');

      Table.cellSpacing = 0;
      Table.cellPadding = 0;

      for (trIDX=0; trIDX < MAX; trIDX++) {
              TR = document.createElement('TR');
              Space = Math.abs(trIDX - parseInt(radius));
              for (tdIDX=0; tdIDX < MAX; tdIDX++) {
                    TD = document.createElement('TD');
                   
                    styleWidth = '1px'; styleHeight = '1px';
                    if (tdIDX == 0 || tdIDX == MAX - 1) styleHeight = null;
                    else if (trIDX == 0 || trIDX == MAX - 1) styleWidth = null;
                    else if (radius > 2) {
                            if (Math.abs(tdIDX - radius) == 1) styleWidth = '2px';
                            if (Math.abs(trIDX - radius) == 1) styleHeight = '2px';
                    }

                    if (styleWidth != null) TD.style.width = styleWidth;
                    if (styleHeight != null) TD.style.height = styleHeight;

                    if (Space == tdIDX || Space == MAX - tdIDX - 1) TD.style.backgroundColor = bdcolor;
                    else if (tdIDX > Space && Space < MAX - tdIDX - 1)  TD.style.backgroundColor = bgcolor;
                   
                    if (Space == 0 && tdIDX == radius) TD.appendChild(obj);
                    TR.appendChild(TD);
              }
              TBody.appendChild(TR);
      }

      /*
              }}
      */

      Table.appendChild(TBody);
     
      // insert table and remove original table
      Parent.insertBefore(Table, objTmp);
}
</script>
사용법)
테이블에 아이디태그가 있어야 합니다.
전 한번 변환하는게 몇개 안되어서 아이디를 입력받아 함수를 실행하도록 했지만, 만약 많은 양을 한꺼번에 변환해야할 경우에는 함수를 변경해서 사용하시기 바랍니다. ^^

위 스크립트를 HTML문서에 포함하고(당연히...),
roundTable(테이블의 아이디문자열);
처럼 함수를 실행시키시면 됩니다.
단, 이 때 원래의 테이블에서 raidus(둥근 정도) 값과 테두리와 배경색의 색상값을 지정하도록 되어있습니다.

int radius : 둥근 정도입니다. 가능한 값은 1 <= radius<= 6 입니다. radius 를 계산하는 부분의 규칙을 잘 몰라서 우선은 한정시켜놨습니다. 나중에 모서리 픽셀을 제대로 구할 수 있게 되면 범위를 수정하겠습니다.

string rborder : 테두리의 색상값. #FFFFFF 와 같은 16진수 색상값과 white 와 같은 색상지시문자열 모두 사용가능.
string rbgcolor : 라운드테이블의 배경색. 배경색은 라운드 테이블 테두리 선 안쪽의 색상을 말하는 것입니다. rborder와 마찬가지로 16진수 색상값과 색상지시문자열 모두 사용가능합니다.

예)
<table id="ta" width="300" height="150" border="0" radius="3" rborder="#999999" rbgcolor="#F8F8F8">
<tr>
      <td>1</td>
      <td>1</td>
</tr>
<tr>
      <td colspan="2">테스트</td>
</tr>
</table>
<script>roundTable("ta");</script>

자세한 것은 링크를 참조하시면 됩니다.

브라우저 정보)
Internet Explorer 5.0 and later
Mozilla 1.5
Firebird 0.6 한글판
Netscapce Navigator 7

위의 두 브라우저에서는 제가 테스트해봤습니다. 다른 브라우저에서도 작동이 잘되면 말씀해주시기 바랍니다. (이 부분은 계속 업데이트 됩니다)
|

No7Do's Blog is powered by Daum & tistory