'Javascript'에 해당되는 글 112건

  1. 2012.04.04 자바스크립트 재귀함수(호출)
  2. 2012.03.24 DOM Interface
  3. 2012.03.20 DOM 노드 및 탐색
  4. 2012.03.16 자바스크립트로 공백 버그 해결하기 4
  5. 2012.03.14 자바스크립트 압축툴 소개 및 사용법
  6. 2012.03.13 자바스크립트 접근자
  7. 2012.03.13 자바스크립트 함수 타입 검사
  8. 2012.03.12 자바스크립트 문자열 타입에 대해서...
  9. 2012.03.12 자바스크립트 배포 및 패키징
  10. 2012.03.09 HTML 조건부 주석

자바스크립트 재귀함수(호출)



재귀함수(호출)란?


정의:

1. 자기 자신을 재호출하는 함수를 말한다.

2. 보통 트리 구조에 대한 알고리즘을 작성할 때 유용하며, 그 외에 여러 가지로 활용할 수 있습니다.


  1. function reflection(base, i)
  2. {
  3.     var r = ''
  4.  
  5.     if (i === 0){
  6.         r = 1;
  7.     }
  8.     else{
  9.         r = base * reflection(base, i - 1);
  10.     }
  11.  
  12.     return r;
  13. }
  14.  
  15.  
  16. reflection(2, 2); // 4


아래는 작성된 재귀함수의 실행 순서를 나타냅니다.


1. reflection() 함수를 호출합니다.

2. reflection() 함수의 매개변수 base와 i의 값으로 각 각 2 가 정의 됩니다.

3. 최초 매개변수 i의 값이 0이 아니므로 조건문 내부의 else 블록({}) 9번라인의 표현식이 실행됩니다.

4. 자바스크립트의 표현식은 오른쪽에서 왼쪽으로 평가되므로 i가 2일 때 재귀호출 reflection(base, i - 1)의 반환 값은 2를 반환하며, 그에 따라 ((base(2)) * (재귀호출 반환 값(2))) 4를 최종 반환합니다.




앞에서도 말했듯이 재귀함수는 트리 구조 탐색에 유용하게 쓰일 수 있다고 하였습니다.


아래는 그에 대한 예제 소스입니다.


  1. // 해당 엘리먼트에 포함된 모든 textNode.nodeValue를 가져온다.
  2. function text(elem, txt)
  3. {
  4.    
  5.     var t = [];
  6.    
  7.     if (!txt)
  8.     {
  9.         elem = elem.childNodes || elem;
  10.  
  11.         for (var i = 0, length = elem.length; i < length; i++){
  12.            
  13.             var e = elem[i];           
  14.             t.push(e && e.nodeType !== 1 ? e.nodeValue : text(e.childNodes));
  15.         }
  16.     }
  17.     else
  18.     {
  19.         t.push(createTextNode(elem, txt));
  20.     }
  21.    
  22.     return t.join('').replace(/(^[\s]*)|([\s]*$)/g, '');
  23. };
  24.  
  25.  
  26. // text 노드 생성
  27. function createTextNode(elem, txt){
  28.    
  29.     elem = elem || document.documentElement;
  30.  
  31.     txt = txt || '';
  32.  
  33.     var $t = document.createTextNode(txt);
  34.    
  35.     elem.appendChild($t);
  36.  
  37.     return text(elem);
  38. };
  39.  
  40. alert(text(null, 'test')); // ....test
  41. alert(text(document.body, 'test')); // ....test
  42. alert(text(document.getElementById('test1'), 'test')); // ....test


작성된 코드에 대해 설명하자면, 함수 매개변수로 해당 엘리먼트와 동적으로 삽입시킬 text를 정의하여 호출할수 있습니다.

또한, 매개변수가 한 개만 있는 경우는 해당 엘리먼트에 포함된 모든 text를 가져오며, 두 번째 매개변수인 text를 정의하면 해당 text가 정의된 text 노드를 반환하게 됩니다.



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

DOM 노드 및 탐색


이번 포스트에서는 공백버그에 대한 내용과 유사한 DOM 노드에 대해 간단히 설명하고 노트 탐색에 필요한 속성값을 알아 보도록 하겠습니다.
 

먼저 DOM에 대해 간단히 정리하자면, XML 구조를 탐색 가능한 트리 형태로 표현하며, 그 최상위 객체로는 문서 엘리먼트
(document documentElement)라고 부르는 단일 노드가 있습니다.
 

또한, 각 노드에는 타입을 반환하는 속성인 node.nodeType이 존재하며, 대표적인 타입으로는 Element, #text, document Element 가 있습니다.

그리고 자신의 직접적인 관계를(부모, 자식, 형제) 가리키는 포인터들과 또 그에 대해 접근할 수 있는 속성들은 아래와 그림과 같이 존재 합니다.





#DOM 트리 구조 관계도




#노드들에 직접 접근할 수 있는 속성들입니다.


  1. document: 문서 자체
  2.  
  3. document.documentElement: 문서의 최상위 루트 엘리먼트 (HTML)
  4.  
  5. parentNode: 부모 엘리먼트
  6.  
  7. previousSibling: 이전 형제 엘리먼트
  8.  
  9. nextSibling: 다음 형제 엘리먼트
  10.  
  11. firstChild: 첫번째 자식 엘리먼트
  12.  
  13. lastChild: 마지막 자식 엘리먼트
  14.  
  15. childNodes: 자식 엘리먼트 집합



그럼 위에 내용을 바탕으로 아래 HTML 코드에 대한 브라우져별 생성 노드에 대해 알아보도록 하겠습니다.

  1. <div>hello<span><strong>wolrd</strong></span></div>



#IE 기준
[body --> div --> #text --> span --> strong --> #text]




#표준 브라우저(FF, Chrome, Safari)
body --> #text(공백버그) --> div --> #text --> span --> strong --> #text --> #text(공백버그)


#Chrome








#FF






위에서도 알 수 있듯이 비표준브라우저와 표준브라우저의 차이점으로는 명백히 공백 버그가 존재하며, 다른점 또한 아래와 같이 존재합니다.


다른점을 알아보기 위해 각 엘리먼트를 nodeType으로 분류한 표를 보시겠습니다.

 

위에서도 볼 수 있듯이 엘리먼트에 대한 계산 여부 또한 브라우저별로 다르다는 것을 한눈에 알 수 있습니다.

또한, 노드타입은 총 12가지로 나뉘지만 실제로 HTML 상에서 다룰 수 있는 타입은 몇 개 되지 않으며, 그중에서도
보통 1번 타입인 Element 노드와 3번 타입인 #text 노드를 노드 탐색 시 주로 다루게 됩니다.








아래 작성된 코드는 노드 탐색에 필요한 함수를 모듈화한 소스입니다.



  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. <script>
  12. var nodes = (function(){
  13.    
  14.     return new (function()
  15.     {  
  16.         function t(){
  17.             return this;
  18.         }
  19.         t.prototype = {
  20.             first: first,
  21.             last: last,
  22.             prev: prev,
  23.             next: next,
  24.             chlid: chlid,
  25.             parent: parent,
  26.             get: get
  27.         }
  28.             return t;
  29.         }());
  30.  
  31.  
  32.         function first(elem){
  33.             elem = elem && elem.firstChild || document.documentElement.firstChild;
  34.             this[0] = elem && elem.nodeType !== 1 ? this.next(elem).get(0) : elem;
  35.             return this;
  36.         };
  37.  
  38.         function last(elem){
  39.             elem = elem && elem.lastChild || document.documentElement.lastChild;
  40.             this[0] = elem && elem.nodeType !== 1 ? this.prev(elem).get(0) : elem;
  41.             return this;
  42.         };
  43.  
  44.         function prev(elem){
  45.             elem = elem || document.documentElement;
  46.             do{
  47.             elem = elem.previousSibling;
  48.             }
  49.             while(elem && elem.nodeType !== 1)
  50.             this[0] = elem;
  51.             return this;
  52.         };
  53.  
  54.         function next(elem){
  55.             elem = elem || document.documentElement;
  56.             do{
  57.             elem = elem.nextSibling;
  58.             }
  59.             while(elem && elem.nodeType !== 1)
  60.  
  61.             this[0] = elem;
  62.             return this;
  63.         };
  64.        
  65.         function chlid(elem){
  66.             elem = elem || document.documentElement;
  67.             var childs = [];
  68.             for (var i = 0, length = elem.childNodes.length; i < length; i++){
  69.             var child = elem.childNodes[i];
  70.             if (child && child.nodeType === 1) childs.push(child);
  71.             }
  72.             this[0] = childs;
  73.             return this;
  74.         };
  75.  
  76.         function parent(elem){
  77.             elem = elem || document.documentElement;
  78.             var parents = [];
  79.             do{
  80.             elem = elem.parentNode;
  81.             if (elem.nodeType === 1) parents.push(elem);
  82.             }
  83.             while(elem && elem.nodeType === 1)
  84.             this[0] = parents;
  85.             return this;
  86.         };
  87.  
  88.         function get(index){
  89.             index = index || 0;
  90.             return this[0] && this[0].length > 0 ? this[0][index] : this[0];
  91.         };
  92. }());
  93. window.onload = function()
  94. {
  95.     alert(nodes.first(document.body).get(0).nodeName); // script
  96.     alert(nodes.last(document.body).get(1).nodeName); // div
  97.     alert(nodes.prev().get()) // null
  98.     alert(nodes.prev(document.body).get(0).nodeName); // head
  99.     alert(nodes.next(document.getElementById('test1')).get(0).nodeName); // div
  100.     alert(nodes.last(document.body).get(2).nodeName); // div
  101.     alert(nodes.chlid().get(1).nodeName); // body
  102.     alert(nodes.parent(document.getElementById('test3')).get(1).nodeName); // html
  103. };
  104. </script>
  105. <div id="test1">
  106. <div id="test2">test2</div>
  107. </div>
  108. <div id="test3">test3</div>
  109. </BODY>
  110. </HTML>



Node 모듈의 각 함수들의 기능은 아래와 같습니다.

  1. #first: 해당 엘리먼트의 첫번째 엘리먼트 반환
  2.  
  3. #last: 해당 엘리먼트의 마지막 엘리먼트 반환
  4.  
  5. #prev: 해당 엘리먼트의 이전 형제 엘리먼트 반환
  6.  
  7. #next: 해당 엘리먼트의 다음 형제 엘리먼트 반환
  8.  
  9. #chlid: 해당 엘리먼트의 자식 엘리먼트 집합 반환
  10.  
  11. #parent: 해당 엘리먼트의 부모 엘리먼트 집합 반환

자바스크립트로 공백 버그 해결하기



오늘은 IE 브라우저와 IE를 제외한 표준 브라우저(FF, Chrome, Safari) 등 에서 DOM 엘리먼트를 다르게 해석하는 경우 중 이미 많이 알려진 공백 버그에 대해 알아 보겠습니다.

말인즉, IE를 제외한 표준 브라우저에서는 엘리먼트 사이에 공백 엘리먼트(줄바꿈)가 존재하며, 브라우저가 이를 하나의 #text 엘리먼트로 간주해 버리는 버그가 있다는 것입니다.


아래는 파이어버그로 본  DOM Element 구조입니다.

보다시피 각 엘리먼트 사이에 공백 엘리먼트(#text)가 존재하는 것을 확인할 수 있습니다.





이 악명 높은 공백 버그 때문에 노드 탐색 시 많은 어려움이 따를수 있으며, 이를 위한 해결하기 위한 방법으로 해당 엘리먼트의 노드 타입을 구분하여 공백 엘리먼트를 제거하는 코드를 작성할 수 있습니다. 



  1. function clearWhiteElement(elem){
  2.    
  3.     elem = elem || document;
  4.    
  5.     var childs = elem.childNodes
  6.       , length = childs.length;
  7.  
  8.     for (var i = 0; i < length; i++){
  9.        
  10.         var child = childs[i];
  11.    
  12.         if (child)
  13.         {
  14.             if (child.nodeType === 3 && !/\S/.test(child.nodeValue)){
  15.                 elem.removeChild(child);
  16.             }
  17.             else if(child.nodeType === 1)
  18.             {
  19.                 clearWhiteElement(child);
  20.             }
  21.         }
  22.         else{
  23.             var n = next(elem);
  24.             if (n) clearWhiteElement(n);
  25.         }
  26.     }
  27. }
  28.  
  29. function next(elem){
  30.    
  31.     do{
  32.         elem = elem.nextSibling;
  33.     }
  34.     while(elem && elem.nodeType !== 1)
  35.  
  36.     return elem;
  37.  
  38. }
  39.  
  40. window.onload = function(){
  41.    
  42.     alert(document.body.firstChild.nodeName); // #text
  43.     clearWhiteElement();
  44.     alert(document.body.firstChild.nodeName); // DIV
  45. }


위 코드를 이용하여 공백 엘리먼트를 제거한 후의 모습입니다.






위에서 보다시피 공백 엘리먼트들이 모두 제거되었으며, 이를 통해 노드 탐색 시 브라우저 특성을 무시할 수 있게
되었습니다.

하지만 공백 엘리먼트를 제거하기 위해 모든 노드를 일일이 탐색하는 비용이 들어가므로 전체 엘리먼트와 같이 많은
엘리먼트를
탐색해야 하는 경우는 되도록 쓰지 않는 것이 좋을 것입니다.


자바스크립트 압축툴 소개 및 사용법



자바스크립트 압축툴 소개 및 사용법


자바스크립트 배포 전 패키징 과정에서 빼놓을 수 없는 작업이 작성된 코드의 압축작업입니다.

아래는 현존하는 자바스크립트 압출툴 중 가장 널리 쓰이고 있는 툴인 JSMIN, Packer에 대해 알아보도록 하겠습니다.





1. JSMin

JSMin의 개념은 자바스크립트 코드를 한 블록씩 들여다보면서 전적으로 어떤 기능을 수행하는 코드만 남기고 다른
불필요한 문자(탭, 줄 끝 문자, 모든 주석)는 모두 제거합니다.



아래는 압축 전/후 코드 상태입니다.


압축전: (jsmin_test.js(294 bytes))

  1. var Priviledge = (function(){
  2.  
  3.     // private
  4.     var p1 = 'p1';
  5.  
  6.     function t(){
  7.         return this;
  8.     };
  9.  
  10.     t.prototype.get = function(){
  11.         return p1;
  12.     };
  13.  
  14.     return t;
  15.  
  16. })();
  17.  
  18.  
  19. alert(new Priviledge().get());




압축후: (jsmin_test.min.js(151 bytes))


  1. var Priviledge=(function(){var p1='p1';function t(){return this;};t.prototype.get=function(){return p1;};return t;})();alert(new Priviledge().get());





- 사용법:




사이트 URL: http://www.crockford.com/javascript/jsmin.html 
툴 URL:http://www.crockford.com/javascript/jsmin.zip






2. Packer


딘 에드워즈가 개발한 Packer는 현존하는 자바스크립트 압축기 중 가장 강력한 성능을 보여주는 압축기이며, JSMIN 과
다르게 base64를 통한 압축 및 지역변수 길이를 짧게 유지시켜 용량을 줄일 수 있는 옵션도 제공합니다.




아래는 압축 전/후 코드 상태입니다.


압축전: (294 bytes)

  1. var Priviledge = (function(){
  2.  
  3.     // private
  4.     var p1 = 'p1';
  5.  
  6.     function t(){
  7.         return this;
  8.     };
  9.  
  10.     t.prototype.get = function(){
  11.         return p1;
  12.     };
  13.  
  14.     return t;
  15.  
  16. })();
  17.  
  18.  
  19. alert(new Priviledge().get());




압축후: (144 bytes)


  1. var Priviledge=(function(){var a='p1';function t(){return this};t.prototype.get=function(){return a};return t})();alert(new Priviledge().get());




사이트 URL: http://dean.edwards.name/packer/


자바스크립트 접근자



자바스크립트 private, public, privileged 메서드


Private, Public, Protected 접근자는 오늘날 대부분 객체지향언어에서 기본적으로 제공하고 있는 기능입니다.

자바스크립에서도 이와 같은 형태는 아니지만, 접근자 구현이 가능합니다.

아래는 자바스크립트에서 구현 가능한 접근자(Private, Public, Privileged)에 대한 설명 및 예제입니다.




1. Private 접근자

Private 변수 및 메서드는 다른 Private 변수 및 메서드 와 Privileged 메서드 에서만 접근 가능하며, 객체 내부에서만 접근 가능합니다.
 



  1. function Private(){
  2.    
  3.     // private 변수
  4.     var p1 = 'p1';
  5.  
  6.     this.p2 = 'p2';
  7.  
  8.     return this;
  9. }
  10.  
  11. // public 메서드
  12. Private.prototype.getP2 = function(){
  13.     return this.p2;
  14. }
  15.  
  16. alert(new Private().p1); // undefined(정의되지 않았음)
  17. alert(new Private().getP2()); // p2




2. Public

Public 변수 및 메서드는 해당 객체 컨테스트 어디서나 접근 가능한 객체 맴버 입니다.


  1. function Public(){
  2.    
  3.     // public 변수
  4.     this.p2 = 'p2';
  5.  
  6.     return this;
  7. }
  8.  
  9. // public 메서드
  10. Public.prototype.getP2 = function(){
  11.     return this.p2;
  12. }
  13.  
  14. alert(new Public().getP2()); // p2




3. Priviledge

Priviledge 변수 및 메서드는 Private 변수에 접근 가능한 Public 객체 맴버입니다.


  1. var Priviledge = (function(){
  2.  
  3.     // private
  4.     var p1 = 'p1';
  5.  
  6.     function t(){
  7.         return this;
  8.     };
  9.  
  10.     t.prototype.get = function(){
  11.         return p1;
  12.     };
  13.  
  14.     return t;
  15.  
  16. })();
  17.  
  18.  
  19. alert(new Priviledge().get()); // p1




Priviledge 구현 방법은 사용성과 효율성에 좋지 않은 방법입니다.

예를 들면 보통 객체 생성 시 재사용 가능한 메서드 맴버 그룹은 프로토타입 맴버에 추가하는 것이 보통이며 효율적입니다.

하지만 이를 구현하기 위해서는 반드시 인스턴스 맴버에 재사용 가능한 메서드를 추가시켜야 하기 때문입니다.



 

자바스크립트 함수 타입 검사



자바스크립트는 언어 특성상 데이터 타입에 대해 까다롭지 않은 언어입니다.
 
죽, 타 언어와는 달리 함수에 전달되는 전달인자의 개수가 다르거나 전달인자의 타입이 다른 경우 해당하는 에러메시지
조차 없다는
말입니다.

함수에 전달되는 전달인자를 나타내는 객체인 arguments 객체를 이용하여 아래와 같이 해당 기능을 구현할 수 있습니다.


  1. function strict(types){
  2.    
  3.     var args = strict.caller.arguments;
  4.  
  5.     if (!types || types.constructor !== Array) return false;
  6.     if (typeof args !== 'object') return false;
  7.  
  8.     var tlen = types.length
  9.       , alen = args.length
  10.       , k = 1;
  11.      
  12.  
  13.     if (tlen !== alen){
  14.         throw new Error('전달인수 갯수가 일치하지 않습니다.');
  15.     }
  16.  
  17.     for (var i = 0; i < tlen; i++){
  18.        
  19.         if (!isDataType(types[i], args[i])){
  20.             throw new Error('호출 함수에 가장 일치하는 오버로드된 메서드의 ' + k + '(' + types[i] + ')' + ' 번째 인수에 잘못된 인수가 있습니다.');
  21.         }
  22.        
  23.         k++;
  24.     }
  25.  
  26.     return this;
  27. }
  28.  
  29. function isDataType(type, arg){
  30.  
  31.     type = type.toLowerCase();
  32.  
  33.     var types = {
  34.         'object': Object,
  35.         'array': Array,
  36.         'function': Function,
  37.         'string': String,
  38.         'number': Number,
  39.         'boolean': Boolean
  40.     };
  41.  
  42.     if (type !== 'newobject')
  43.     {
  44.    
  45.         if (types[type]){
  46.             if (arg.constructor === types[type]) return true;
  47.             else return false;
  48.         }
  49.     }
  50.     else
  51.     {
  52.         // typeof 연산자만 가지고는 new Function() 타입을 가려낼 수 없습니다.
  53.         if (arg.constructor !== Object && arg.constructor !== Array && typeof arg === 'object') return true;
  54.         else return false;
  55.     }
  56. };
  57.  
  58. function fn(obj, obj, arr, fn, str, num, bls){
  59.     strict(['object', 'newobject', 'array', 'function', 'string', 'number', 'boolean']);
  60. };
  61.  
  62.  
  63. // 아래는 각각 다른 타입의 전달인자를 넣어 호출 하는 예입니다.
  64.  
  65. var a = function() { ; };
  66. fn({}, new a(), [], function(){ ; }, 'str', 1, true);
  67. fn({}, {}, [], function(){ ; }, 'str', 1, true);
  68. fn({}, [], [], function(){ ; }, 'str', 1, true);


arguments 객체를 활용하여 위와 같은 구현은 가능하지만 모듈개발 시 잘 쓰이지 않는 것이 보통입니다.

하지만 알맞은 타입검사는 그만큼 해당 모듈의 에러를 줄여주는 역할을 합니다.

자바스크립트 문자열 타입에 대해서...




이전 포스트 내용 중 문자열 타입에 관해 얘기 했던 적이 있습니다. 포스트 내용에 핵심은 문자열 타입이 "값"과 "참조" 중
어디에 속하는지에 대한 얘기였으며, 이번 포스트에서 그에 관한 얘기를 더 나눠보도록 하겠습니다.


우선 자바스크립트 문자열은 가변적인 길이를 가지고 있습니다, 이 말은 고정되어 있지 않다는 말이며, 그 때문에 고정된
메모리를 가진 변수에는 직접 저장할 수 없다는 말이며(값 타입처럼), 대신, 변수에 저장되는 것은 이런 값에 대한 "참조 값"입니다.


그렇다면, 문자열은 "참조타입"이라는 걸까요?





아래 예제를 통해 더 자세히 알아보도록 하겠습니다.


  1. // 참조타입의 기본 예
  2.  
  3. // r 배열객체는 참조타입이므로 r1 배열객체와 같은 값을 참조하며, r 배열객체와 r1 배열객체는 같습니다.
  4. var r = [];
  5. r[0] = 'hello';
  6.  
  7. var r1 = r;
  8. r1[1] = 'world';
  9.  
  10. alert(r === r1); // true
  11.  
  12. // 문자열이 값타입이라는 예
  13.  
  14. // v 문자열 객체는 값타입이므로 새로 생성된 문자열 객체 v1과 다릅니다.
  15. var v = 'hello';
  16. var v1 = v + 'world';
  17.  
  18. alert(v === v1); // false


위 결과에서 말하는 바와같이 자바스크립트 문자열은 내부적으로 참조타입의 효율성을 갖도록 구현된 기본타입입니다.

즉, 기본타입이면서 참조타입이 가지고 있는 효율성만 갖도록 구현되었다는 말입니다.

자바스크립트 배포 및 패키징




자바스크립트 배포 및 패키징


라이브러리 작성 후 마지막으로 해야 할 일은 보통 작성된 코드를 패키징하고 사용자들에게 배포하는 일일 것입니다.

하지만 스크립트 언어 특성상 배포된 코드의 전역변수 이름과 기존 코드의 전역변수 이름이 동일한 경우 나중에 로드된 코드가 이전 코드를 모두 덮어 버리는 현상이 발생하게 됩니다.

즉, CSS 코드와 마찬가지로 코드를 Cascading 해버린다는 뜻이며, 또한 이런 이유로 배포된 라이브러리가 정상적으로 동작하지 않게 됩니다.

이를 해결하기 위한 방법의 하나가 네임스페이스를 이용한 방법이며, 이는 현재까지 가장 널리 쓰이는 방법이기도 합니다.




아래 코드는 패키징에서 배포까지의 작업을 나열한 것입니다.

  1. var NAVER = window.NAVER || {};
  2. window.NAVER.ajax = window.NAVER.ajax || {};
  3.  
  4.  
  5. window.NAVER.ajax = (function(doc, win){
  6.    
  7.     var xhr = getXhr()
  8.       , version = '1.0.x'
  9.       , agent = window.navigator.userAgent.toLowerCase();
  10.    
  11.     return new (function(){
  12.        
  13.         var t = function(){
  14.            
  15.             this.version = version;
  16.        
  17.             return this;
  18.         };
  19.        
  20.         t.prototype = {
  21.             get: get,
  22.             post: post
  23.         };
  24.  
  25.         return t;
  26.  
  27.     }())();
  28.    
  29.     function getXhr(){
  30.  
  31.         if (!window.XMLHttpRequest) return new ActiveXObject(agent.indexOf('msie 5') > -1 ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP');
  32.         else if (window.XMLHttpRequest) return new window.XMLHttpRequest;
  33.         else return null;
  34.     }
  35.  
  36.  
  37.     function get(){
  38.         return this;
  39.     }
  40.  
  41.  
  42.     function post(){
  43.         return this;
  44.     }
  45.  
  46.  
  47. })(document, window);
  48.  
  49.  
  50. alert(window.NAVER.ajax.get().version); // 1.0.x


위와 같은 방법으로 패키징하며, 사용자들에 배포하게 됩니다.

HTML 조건부 주석



웹 개발시 IE 버전마다 조금씩 다르게 작동하는 브라우저 버그와 자바스크립트 비호환 문제로 인해 크로스 브라우징 개발 시 많은 애를 먹었을 것입니다.

이를 보안하기 위한 수단으로 아래와 같은 HTML 주석을 활용한 처리 방법이 있습니다.



위와 같은 방법을 통해 정리 되지 않는 CSS 및 자바스크립트 코드를 버전별로 구분하여 해당 구성요소들을 로드시킬수
있습니다.



 


prev 1 ··· 4 5 6 7 8 9 10 ··· 12 next