DOM Interface


IE를 제외한 대부분의 표준 브라우저(파폭, 사파리, 크롬, 오페라)에서는 HTMLElement 라는 인터페이스가 존재합니다.

- 여기서 인터페이스란? 

간단히 말해 개발자 언어(java, javascript)와 DOM 의 의사소통을 담당하는 중간 매개체로 볼 수 있습니다.

"개발자는 DOM 내부 구현에 대한 지식 없이 다양한 언어(java, javascript, ect)를 통해 객체와 인터페이스로 문서에 접근 할 수 있습니다.

즉, 자바스크립트를 통해 생성된 엘리먼트는 고유의 인터페이스를 제공받게 되는 것입니다."

아래는 위에서 설명드린 부분을 보여주는 소스코드 입니다.



  1. if (HTMLElement)
  2. {
  3.     // 각 엘리먼트들은 object를 취하며, 고유의 인터페이스를 제공받습니다.
  4.  
  5.     alert(document.createElement('div')); // object HTMLDivElement && HTMLDivElement interface
  6.     alert(document.createElement('img')); // object HTMLImageElement && HTMLImageElement interface
  7.     alert(document.createElement('input')); // object HTMLInputElement && HTMLInputElement interface
  8. }

 
아래 DOM Interface를 나타내는 그림에서처럼 DOM에 접근하기 위한 가장 상위 인터페이스는 Document이며, 

그 하위 인터페이스인 HTMLELement 는 Elemenet 인터페이스를 상속받아 구현되고 그 아래는 문서의 모든 엘리먼트들이
존재합니다. 


 


 


또한, 아래 그림은 DOM 탐색 시 쓰이는 함수 목록이며, 노란색 부분은 그중에서도 자주 쓰이는 함수를 나타낸 것입니다.





그럼 이제부터 HTMLElement 인터페이스를 활용하여 문서의 모든 엘리먼트에 객체 맴버를 추가 시킬 수 있는 방법에 대해
알아보도록 하겠습니다.



- HTML 소스

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <TITLE> New Document </TITLE>
  5. <META NAME="Generator" CONTENT="EditPlus">
  6. <META NAME="Author" CONTENT="">
  7. <META NAME="Keywords" CONTENT="">
  8. <META NAME="Description" CONTENT="">
  9. </HEAD>
  10. <BODY>
  11. <div id="test1">
  12.     <div id="test1_1"></div>
  13. </div>
  14. <div id="test2">test2</div>
  15. <div id="test3">test3</div>
  16. </BODY>
  17. </HTML>



- 공통 함수 

  1.      // 객체 상속 함수
  2.     function extend(){
  3.        
  4.         var target = this
  5.           , opts = []
  6.           , src = null
  7.           , copy = null;
  8.  
  9.         for (var i = 0, length = arguments.length; i < length; i++) {
  10.            
  11.             opts = arguments[i];
  12.            
  13.             for (var n in opts) {
  14.                 src = target[n];
  15.                 copy = opts[n];
  16.  
  17.                 if (src === copy) continue;
  18.                 if (copy) target[n] = copy;
  19.             }
  20.         }
  21.     }
  22.  
  23.    
  24.     // 각 맴버가 추가 되어있는 객체
  25.     var nodes =
  26.     {
  27.         prev: function(){
  28.            
  29.             elem = this;
  30.            
  31.             do{
  32.                 elem = elem.previousSibling;
  33.             }
  34.             while(elem && elem.nodeType !== 1)
  35.            
  36.             return elem;
  37.         },
  38.  
  39.         next: function(){
  40.            
  41.             elem = this;
  42.            
  43.             do{
  44.                 elem = elem.nextSibling;
  45.             }
  46.             while(elem && elem.nodeType !== 1)
  47.  
  48.             return elem;
  49.         }
  50.     }


아래는 HTMLElement 인터페이스를 지원하는 표준 브라우저 방식의 코드입니다.


  1.      // 표준 브라우저 방식
  2.     // HTMLElement 하위의 모든 엘리먼트에 nodes객체의 모든 맴버를 추가 시킵니다.
  3.     if (window.HTMLElement){
  4.  
  5.         extend.call(window.HTMLElement.prototype, nodes);
  6.        
  7.         alert(document.getElementById('test3').prev().prev().next().id); // test2
  8.  
  9.     }


위에서 언급한 바와 같이 IE 브라우저는 HTMLElement 객체를 제공하지 않습니다.

하지만
IE 브라우저 에서도 아래와 같이 유사 기능을 구현할 수 있습니다.


  1.      // 비표준 브라우저 방식   
  2.     if (!window.HTMLELement){
  3.        
  4.         var fnCreate = document.createElement
  5.           , fnId = document.getElementById
  6.           , fnTags = document.getElementsByTagName;
  7.  
  8.         /*
  9.         document.createElement = function(tag){            
  10.             var o = fnCreate(tag);
  11.             o && extend.call(o, nodes);
  12.             return o || undefined;
  13.         };
  14.  
  15.         document.getElementsByTagName = function(tag){             
  16.             var o = fnTags(tag);
  17.             o && extend.call(o, nodes);
  18.             return o || undefined;
  19.         };
  20.  
  21.         */
  22.        
  23.        
  24.         // document 객체의 맴버함수를 오버라이하여 구현합니다.
  25.         document.getElementById = function(id){            
  26.             var o = fnId(id);
  27.             o && extend.call(o, nodes);
  28.             return o || undefined;
  29.         };
  30.  
  31.         alert(document.getElementById('test2').prev().id); // test1
  32.         alert(document.getElementById('test1').next().id); // test2
  33.    
  34.     }


아래 코드는 이전에 구현되지 않았던 함수 체인방식이 적용된 코드입니다.


  1. var nodes =
  2.     {
  3.         prev: function(){
  4.            
  5.             elem = this[0] || this;
  6.            
  7.             do{
  8.                 elem = elem.previousSibling;
  9.             }
  10.             while(elem && elem.nodeType !== 1)
  11.  
  12.             this[0] = elem;
  13.  
  14.             // 이전 코드처럼 elem를 반환하지 않고 getElementById 함수 호출시 nodes객체의 모든 맴버가 추가 되어있는 'test2' 객체를 반환하여 체인방식을 적용시킵니다.
  15.    
  16.             return this;
  17.         },
  18.  
  19.         next: function(){
  20.            
  21.             elem = this[0] || this;
  22.            
  23.             do{
  24.                 elem = elem.nextSibling;
  25.             }
  26.             while(elem && elem.nodeType !== 1)
  27.  
  28.             this[0] = elem;
  29.            
  30.             return this;
  31.         }
  32.     }
  33.  
  34.     if (!window.HTMLELement){
  35.         var fnCreate = document.createElement
  36.           , fnId = document.getElementById
  37.           , fnTags = document.getElementsByTagName;
  38.  
  39.         /*
  40.         document.createElement = function(tag){            
  41.             var o = fnCreate(tag);
  42.             o && extend.call(o, nodes);
  43.             return o || undefined;
  44.         };
  45.  
  46.         document.getElementsByTagName = function(tag){             
  47.             var o = fnTags(tag);
  48.             o && extend.call(o, nodes);
  49.             return o || undefined;
  50.         };
  51.  
  52.         */
  53.  
  54.         document.getElementById = function(id){            
  55.             var o = fnId(id);
  56.             o && extend.call(o, nodes);
  57.             return o || undefined;
  58.         };
  59.  
  60.         alert(document.getElementById('test2').prev().next()[0].id); // test2
  61.    
  62.     }


지금까지 문서의 모든 엘리먼트에 객체 맴버를 추가 시킬 수 있는 방법에 대해 알아보았습니다.  하지만 이 방법은 실무에서 거의 사용되지 않는 것이 사실입니다.

즉, DOM 인터페이스를 학습하기 위한 코드이며, 더 많은 학습을 원하고 실무에서 사용 가능한 코드를 작성하고 싶다면 cssQuery 나 jQuery 의 내부 로직 중 DOM 탐색에 대한 부분을 분석하는 것을 추천합니다.





참고 사이트:

DOM Interface in javascript- @Rhio.Kim's blog 
http://rhio.tistory.com/198