[독후감]Ajax DOM 스크립팅

ajax_dom_scripting

올해 처음으로 읽은 기술서적이다.  저자인 김영보님은 페이스북을 통해 알게되었고,

기본“을 중요시하는 책 소개를 보고 망설임없이 책을 선택했다.

클라이언트 사이드는 서버사이드에 비해 많이 부족한 것이 사실이었고, 막상 사용자가

접하게 되는 최종경로가 “유저 인터페이스“임에도 불구하고 그 동안 너무 무관심(?)하게

대하지 않았나 하는 반성과 함께 책을 읽어나갔다.

다 읽고 난 후 일단, 기존에 몰랐던 DOM(Document Object Model)에 대한 기본적인 이해와

함께 “자바(Java)“처럼 인터페이스를 통해 각 기능이 제공하는 프로퍼티와 메서드에

접근할  수 있다는 것을 알았다.

그리고 DOM을 사용하는 궁극적 목적인 “역동적인 유저 인터페이스를 실현“하기 위함

이라는 것도 알게 되었다.

그리고 이 책 덕분에 W3C에서 DOM API Specification도 살펴보게 되는 계기가 되었다.

가장 좋았던 것은, 중간중간 깨알같이 나오는 문구들이다. 저자의 깊은 지식과 경험을

엿볼 수 있는 대목이기도 하다. 예를 들면 아래와 같다.

객체지향 프로그램을 개발함에 있어 가장 기본적인 접근은 더 이상 기능을 나눌 수

없을 때까지 상세하게 분리하는 것이다.

다만, 한가지 아쉬운 것은 DOM API를 기준으로 설명하다보니 책을 읽어 나가는 것이

다소 지루할 수 있다는 것이다.

그리고 책에 나와있는 예제들을 직접 실행해보지 않은 것도 아쉬움으로 남는다.

이 책에 있는 예제들의 prototypejs를 jquery로 변경해서 연습해보는 것도 좋을것이다.

서버사이드에 비해 클라이언트 사이드가 관심이 적은 건 사실이지만, 앞서 얘기한 대로

클라이언트 사이드를 무시하고 소프트웨어를 개발한다는 것은 어불성설이기 때문에

서버사이드와 함께 꾸준히 관심을 가지고 공부해 나갈 생각이다.

다음엔 아마 자바스크립트를 공부하지 않을까 싶다. ^^

Advertisements

[번역]간단한 자바스크립트 상속

원본 : http://ejohn.org/blog/simple-javascript-inheritance/

난 최근에 자바스크립트 상속에 관해 많은 일을 해왔다.

다시말해 “자바스크립트 책 안에서의 내 일“을 위해서, 그리고  다수의 다른

자바스크립트의 고전적인 상속 시뮬레이팅 기술에 대해 시험해왔다.

내가 보고 생각한 것 중 가장 좋아하는 것은 “base2“와 “Prototype“에 의해

사용된 구현이었다.

난 이런 기술들에서 간단하고, 재사용하고,어떤 의존성 없이 쉽게 이해할 수 있는 양식

가지는 기술을 뽑아내기를 원했다.

부가적으로, 난 간단하면서도 사용성이 높은 결과가 나오길 원했다.

여기 당신이 그것을 사용할 수 있는 예제가 있다.

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  },
  dance: function(){
    return this.dancing;
  }
});
var Ninja = Person.extend({
  init: function(){
    this._super( false );
  },
  dance: function(){
    // Call the inherited version of dance()
    return this._super();
  },
  swingSword: function(){
    return true;
  }
});

var p = new Person(true);
p.dance(); // => true

var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true

// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class

이 구현에 대해 주목해야 할 것들은..

  • 생성자 생성이 간단하다(이 경우 init method의 간단한 제공으로 트릭을 썼다)
  • new ‘class’의 생성을 위해 존재하는 클래스를 확장할 수 있다.
  • 하나의 조상(Class)으로부터 상속받은 모든 ‘classes’들은 클래스이다.
    그러므로, 새로운 클래스를 만들길 원한다면 그것은 Class의 sub-class일 것이다
  • 가장 도전적인 것 : 오버라이드 된 메서드에 접근하는 것도 제공된다
    (그들의 전적인 문맥에 맞춰) 당신은 this._super(), Person super-class에서
    init()과 dance()메서드를 호출하는 것을 사용하는 걸 볼 수 있다.

난 결과를 기쁘게 생각한다. 그것은 구조로서의 “classes”의 개념을 강화하는 데 도움을 줬고

간단한 상속을 유지하고, 슈퍼 메서드 호출을 허용한다.

-간단한 클래스 생성과 상속-

여기 25라인에 걸쳐 꽤나 합리적인 사이즈에 주석이 잘 달린 구현이 있다.

피드백은 환영하고 감사드린다.

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
  // The base Class implementation (does nothing)
  this.Class = function(){};

  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;

    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;

            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];

            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);
            this._super = tmp;

            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }

    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = prototype;

    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;

    return Class;
  };
})();

두개의 교묘한 부분에 대한 내 의견은 “초기화/init을 호출하지 않고“,

_super 메서드를 생성“하는 부분이다.

난 저 부분에 대해 간단히 다루길 원했고, 그래서 이 메서드를 구현하는 것에

대한 잘 이해할 수 있을 것이다.

–  초기화 – 

function prototype과 함께 상속을 모의시험하기 위해 우리는 super-class의

객체를 생성하는 전통적인 기술을 사용했고 그것에 prototype을 할당했다.

그것을 이와 같이 사용할 수 있을 것이다.(?)

function Person(){}
function Ninja(){}
Ninja.prototype = new Person();
// Allows for instanceof to work:
(new Ninja()) instanceof Person

이것에 대한 도전은, Person객체를 설명하는 전체 비용 없이 ‘instanceof’의 이익이

우리가 정말로 원하는 모든 것이다. 우리 코드안의 변수에 대응하기 위해,

initializing(초기화), prototype을 위해 그것을 사용하는 단 하나의 목적과 함께

우리가 클래스  상속을 할때는 언제든지 그것은 맞는 조합이다.

그래서 함수를 정말로 만들 시점에, 우리는 초기화 메서드가 필요하지 않고

정확히는 init method를 실행한다.

if ( !initializing )
  this.init.apply(this, arguments);

이것에 관해 특별히 중요한 것은 init method가 비용이 많이 드는 시작코드의 모든 종류를

실행할 수 있다(서버 연결, DOM 요소 만들기) 그래서 일하는 데 처해지는 어려움을 제법 잘

피하게 된 것이다.

-슈퍼 메서드-

당신이 상속을 할때, 슈퍼 클래스로부터 기능을 상속하는 클래스를 만드는 것은,

자주 쓰이는 것은 당신이 오버라이드 한 메서드에 접근하는 능력이다.

마지막 결과로, 이 특별한 구현안에, 서브 클래스의 메서드 안으로부터

오직 접근가능한, 슈퍼 클래스와 연결된 메서드를 참조하는 새로운

임시 메서드(_super)가 있다.

예를 들면, 슈퍼 클래스의 생성자를 호출하길 원한 경우 이런 기술을

사용할 수 있다.

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  }
});
var Ninja = Person.extend({
  init: function(){
    this._super( false );
  }
});

var p = new Person(true);
p.dancing; // => true

var n = new Ninja();
n.dancing; // => false

이 기능의 구현은 몇가지 스텝이 있다. 시작을 위해, 우리가 이미 존재하는 클래스를

확장해 사용하는(Person.extend와 같은), 새로운 Person 객체의 기초위에 합쳐져야

할 필요하기 있는(이전에 기술된 구조 위에) 객체 리터럴에 주목하라.

우리는 간단한 체크를 한다 : 우리가 기능을 합치는 시도, 그리고 또한 기능을

대체하는 것에 대한 소유가 있는가? 우리는 새로운 슈퍼 메서드가 하는 일을

위한 방법을 만드는 것이 필요하다.

새로운 강화된 슈퍼 메서드를 압축하게 될 익명의 종결(함수가 리턴되는) 을

만든다.  To start we need to be ad good citizen(?), 기존의 this._super에 참조를

저장한다(실제 존재하는 걸 무시하고) 그것은 우리가 한 이후에 회복한다.

이것은 같은 이름이 이미 존재하는(사고로 그것을 떠나보내길 원하지 않는)

변수가 있는 곳에 대한 경우에 도움을 줄 것이다.

다음으로 우리는 슈퍼클래스의 prototype에 존재하는 메서드의 참조를 가진

새로운 _super메서드를 만든다. 고맙게도 우리는 어떤 부가적인 변화를

만들지 않아도 된다. 여기 함수의 문맥처럼 우리 객체(이것은 슈퍼클래스에

반대는 객체를 참조할 것이다)의 소유를 자동으로 조합할 것이다.

마침내 우리는 우리의 원래 메서드를 호출한다. 그것은 자신의 역할을 수행한다

후에 우리는 그것의 원래 상태에 _super를 회복하고 함수로부터 리턴받는다.

지금 간단한 결과를 구현한 대한 다양한 방법이 있다.

(인자들로부터 접근가능하고, 그 자신의 메서드에 슈퍼 메서드의 경계를 가지는

구현을 본) 그러나 난 유용함과 간단함의 최고 조합을 이 기술이 제공했으리라

느낀다.

난 나의 완벽한 일 안에 자바스크립트 prototype system뒤에 nitty-gritty의 많은

것이 담겨져 있을 것이다.

하지만  난 이 클래스 구현으로 부터 그것을 시도하고 구현함에 있어 모든 것을

얻기를 바란다. 나는 이 간단한 코드(배우기 쉽고, 확장하기 쉽고, 다운로드에

부담이 없는)에 많은 것을 말할 수 있으리라 생각한다.

그래서 난 이 구현이 좋은 출발점이 되리라 생각하고 자바스크립트 클래스 구조와

상속의 기본을 배울 수 있다.

[javascript]john Resig 라이브러리를 통한 object 코딩 실습

전에 자바스크립트 object 코딩실습에 대한 포스팅을 올린 적이 있습니다.

자바스크립트 객체를 만들어 사용하는 법과 연괄배열을 사용하는 법에 대해 간단히

실습해봤는데요. 이번엔 john Resig이 만든 라이브러리를 통해 실습을 해보도록 하겠습니다.

================================================================

우선 위의 블로그를 보시면 아시겠지만, 자바스크립트 객체를 상당히 간단하게(!) 만들어

사용할 수 있습니다.

일반적으로, OOP와 자바프로그래밍을 하실 수 있는 분이라면 무리없이 코딩이 가능합니다.

거두절미하고 아래 예제코드를 보시죠.

<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="resig.js"></script>
<script language="javascript">
(function ($) {
    "use strict";

    if(typeof window.bluepoet == "undefined") {
          window.Bluepoet = {};
    }

    Bluepoet.Parent = Class.extend({
        name : '',
        init: function(name) {
            var me = this;
            me.name = name;
        },
        getName: function() {
            var me = this;
            return me.name;
        }
   });

   Bluepoet.Child = Bluepoet.Parent.extend({
       init:function(name) {
           return this._super(name);
       }
   });
})(jQuery);

$(document).ready(function() {
    var parent = new Bluepoet.Parent("parent");
    var child = new Bluepoet.Child("child");

    document.write(parent.getName() + " : " + child.getName());
});
</script>
</head>
<body>
</body>
</html>

위 코드의 결과는 각각 Parent, Child 클래스의 이름인 “parent : child”가 나오게 됩니다.

코드를 간단히 설명드리면,

우선, “Bluepoet”이란 전역객체를 선언하고 Bluepoet에 각각 Parent와 Child 클래스를

선언했습니다. 이때, john Resig이 만든 라이브러리르 사용하여 클래스를 만듭니다.

내용은, init 메서드로 자바스크립트 클래스의 생성자를 만들고, 자바 클래스와 동일하게

안에 필드와 메서드를 만들어 사용할 수 있습니다.

최종적으로, Parent와 Child 클래스를 생성할 때 생성자에 각자의 이름을 넣어주고

객체를 생성해서, 각자의 이름을 출력하게 됩니다.

Parent에 init과 getName 메서드에 this를 대입한 “me” 변수를 선언한 이유는

객체자신을 제외한 이벤트객체와의 차별화를 위해 따로 정의를 한 것입니다.

두 객체 다 자기자신을 모두 this로 사용하기 때문에 나중에 있을 혼란을 미연에

방지하기 위해서이죠.

끝으로, 윗단에 “use strict”라고 명시해 놓은 것은 strict mode에서 자바스크립트

컴파일 과정에 더욱 엄격한 체크를 하겠다는 선언입니다.

위 내용에 대한 설명은 아래 링크를 참조하시면 됩니다.

자바스크립트 코드를 객체지향적으로 만들게 되면, 기존보다 코드량이 훨씬

줄어들뿐만 아니라, DOM에서의 요소검색에서도 월등한 성능향상을

기대할 수 있습니다.

자~! 이제 자바스크립트 객제지향코드의 바다로 풍덩~ 빠져보시죠^^

[javascript]object 코딩 실습

제가 대학다닐 때, 그러니까 1999년부터 2006년 사이에는

자바스크립트“하면 저는 그저 인터넷에 돌아다니는 몇몇 스크립트 긁어다가 붙여 쓰는게

다였습니다. 그 만큼 개념이 없었죠. ㅡㅡ;

하지만 지금은 그 중요성이 날로 증대되고 있는 상황이니 참 짧은 시간이지만

격세지감을 느낍니다.

저도 요즘 “ppk 자바스크립트“를 출근길에 보면서, “내가 자바스크립트 공부도 하는구나~!”

라는 사실이 가끔씩 새롭게 느껴질 때가 있습니다.

================================================================

각설하고, 잠깐 책에 나온 “자바스크립트 코어“부분에 나온 “객체“에 소개된 부분을

토대로 예제코드를 만들어 보았습니다.


<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script><script type="text/javascript" language="javascript">// <![CDATA[
var test = {
	a : 2,
	b : '2',
	c : function() {
	    return this.a*this.b;
	}
};

$(document).ready(function() {
    /*
    for(var i in test) {
        alert(test[i]);
    }
    */

    //document.write(test['c']());
    document.write(test.c());
});
// ]]></script>

결과는 예상하신대로, “4”가 브라우져에 출력되게 됩니다.

test 객체의 b 프로퍼티의 값은 c메서드에서 숫자로 자동인식하여 2*2=4의 결과를

만들어내게 됩니다.

위 예제에서 for문의 주석을 풀고 결과를 확인하시면 test 객체의 각 프로퍼티와 메서드가

출력됩니다.  c메서드는 본문 전체가 나오게 됩니다.

그리고 마지막에 test객체의 c메서드를 호출할때, “연관배열“을 사용할 수도 있습니다.

연관배열“의 정의를 책에서 빌려오면

  • 어떤 값의 이름 문자열을 사용해 그 값을 찾을 수 있게 해주는 배열

이라고 소개되어 있습니다. a프로퍼티는 test[‘a’] 저런식으로 가져오면 되겠죠.

자바스크립트에도 자바와 동일하게 try-catch-finally가 있어 헷갈리던 시절…

이제 자바스크립트도 자바처럼 “객체지향적“으로 “멋지게” 코딩할 수 있는 날이

어서 왔으면 좋겠네요. 많은 단련을 해야겠습니다. ^^

[javascript]암묵적 전역변수 실습 – 안티패턴

오늘 출근하면서 “ppk 자바스크립트” 5장 코어를 보는 와중에 “var“를 선언하지 않은

변수는 함수 밖이든 안이든 모두 전역변수가 된다는 글을 보았습니다.

제 상식에는 함수 안에서 쓰면 무조건 지역변수가 되야 할 것 같은데 자바스크립트는

명시적으로 변수 앞에 “var“를 붙여주지 않으면 암묵적 전역변수가 된다고 합니다.

그래서, 아래 테스트코드를 만들어 보았습니다

<html>
<head>
<script src="../jquery.1.6.min.js"></script>
<script language="javascript">
$(document).ready(function() {
    globalVariableTest();
    print(x);
});
var print = function(val) {
    document.write("global variable x value : " + val);
}

function globalVariableTest() {
    var y = 4;  //함수내 지역변수
    x = y*2;    //암묵적 전역변수
}

</script>
</head>
<body>
</body>
</html>

결과는 변수 x를 선언하지 않았다는 오류가 나올것 같지만 의외로 아래와 같은 결과가

나옵니다.

globalVariableTest() 함수가 실행되면,  x는 암묵적으로 “전역변수“가 되어  document

body에 x의 값이 찍히는 것입니다.

하지만 이것은 “안티패턴“이라고 하네요.  되도록

  • 전역변수를 최소화하라
  • 변수를 선언할때는 명시적으로 “var“를 쓰고, 단일 var패턴을 사용하라.

저렇게 “자바스크립트 코딩기법과 핵심패턴“에 나와있다고 하네요. 저도 나중에 꼭

읽어볼 책입니다.

단일 var패턴“에 대해 궁금하시면 링크를 참고하세요.

여튼,  결론은

  • 변수는 꼭 “var“를 써서 명시적으로 선언하고,  “단일 var“패턴을 사용하라!

[jquery].each 테스트 예제

회사 jquery의 each에 대한 소스를 보던 중.. 이해 안가는 부분이 있어 예제를 만들어 보았다.

(1) 먼저 jquery 스크립트가 없는 일반적인 테이블 그림이다.

   

<table class="test" border="1">
<tbody>
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>5</td>
<td>6</td>
</tr>
</tbody>
</table>
<pre>

(2) 이걸 each api를 써서 번호를 거꾸로 쓰는 예제를 만들어 보았다.

$(document).ready(function() {
 var cnt = 6;

 $('.test tr:first td').each(function(k, v) {
 $('.test tr').each(function() {
     var $table = $(this);
     $table.find("td").eq(k).html(cnt);

     if(cnt &gt; 3) {
         $table.find("td").eq(k).css('background-color', 'red');
     }else{
         $table.find("td").eq(k).css('background-color', 'yellow');
     }
     cnt--;
     });
   });
});

처음엔 머리로만 소스를 이해하려고 하다보니, 왜 왼쪽부터 아래로 내려가며 순번이

매겨질까 한참을 생각하다가, 역시 예제코드를 보며 알게 되었다.

역시 개발자는 백문이 불여일타라는 생각이 다시 들었다.

jquery each api에 대한 링크는 jquery each API에서 찾아볼 수 있다.

[소스코드]