2015-01-12
변수 $ 을 Jquery 함수로 매핑
jQuery의 기본 프로토타입 객체를 버리고 jQuery.fn 을 jQuery.prototype으로 지정
jQuery의 기본 프로토타입객체는 constructor프로퍼티 만을 가지고 있는 객체. jQuery.fn을 jQuery의 프로토타입으로 지정하고 메서드를 추가.<div id="mydiv">hello</div> <script>alert($("#mydiv").text())</script>이 코드를 jquery가 어떻게 처리하는지.jQuery("#myDiv")
[1~3] 첫 인자 a 는 #mydiv 이므로 a.constructor 값은 string이 된다. a.constructor 가 Function이 되는경우는 a가 함수일때 이다. 고로 이 if는 패스한다. [5~6] a의 값이 이미 #mydiv 라는 값이 있기때문에 패스. a의 디폴트값을 저장하는 코드. [8~10] a 는 #mydiv 라는 문자열이기 때문에 a.jquery 와 같이 프로퍼티를 가지고있지 않다. jquery프로퍼티는 jQuery객체가 프로토타입 체이닝으로 접근할 수 있는 값이기 때문에 a가 jQuery객체인지 확인하는 조건문 이라 볼 수 있다.
[1~3] c 가 jQuery객체인지 확인한다. [5~7] this 가 window로 잡히는것은 jQuery가 함수형으로 호출되었을 때 이다. jQuery가 함수형으로 호출되었을때는 new 연산자와 함께 생성자함수 형태로 다시 호출한다. 생성자 형식으로 호출하였을때 이 객체는 jQuery객체로서 jQuery.prototype객체를 자신의Prototype으로 연결. 생성자로 호출되었을시 this는 jQuery객체가 되기때문에 넘어간다. [9~11] 자바스크립트에서 / 는 정규표현식을 만드는 기호이다. 정규 표현식에 대해서는 깊게 다루진않고 ^[^<]*(<.+>)[^>]*$ 을 분석해보자.
^: 문자열의 시작을 나타낸다. [^<]* : [ ] 안에 포함된 ^ 는 지정한 문자를 제외하라는 의미이다. 즉 [^<] 는 < 를 제외한 모든문자를 의미. (<.+>) : () 는 캡처 그룹을 나타낸다. 괄호로 묶인 정규표현식에 일치하는 부분은 캡쳐된다. '.' 는 줄바꿈을 제외한 아무문자. 그리고 + 는 한개 이상을 나타내는 수량자이다. 즉. <>로 둘러싸인 문자나 문자열. HTML태그 형태를 캡쳐하는 정규표현식 [^>]* : 빈 문자열이나 > 문자를 제외한 문자나 문자열 $ : 문자열의 끝 을 나타낸다.
1. 빈 문자열이나 < 문자를 제외한 문자나 문자열로 시작하고 2. 중간에 <> 형태의 문자나 문자열이 있으며 3. 빈 문자열이나 > 문자를 제외한 문자나 문자열로 끝난다.
예제에서는 #myDiv 문자열이 인자로 넘겨진다. 이 문자열은 정규표현식에 일치되는부분이 없기떄문에 exec()의 결과는 null 이 된다.this.get 메서드를 호출하는 코드이다. 인자가 조금 복잡하게 되어있으니 이걸 먼저 확인해보자. 삼항 연산자 형태로 조건이 true면 jQuery.merge(), false면 jQuery.find()를 호출한다.
1. a.constructor == Array (false): a.constructor은 String 이다. 고로 패스 2. a.length (true) : a 는 문자열이기에 length 프로퍼티가 있고 문자열길이를 의미함. 3. !a.nodeType(false) : nodeType 은 DOM객체가 가지는 프로퍼티이다. a는 문자열이므로 없음! 4. a[0] != undefined (true) : a는 문자열이므로 인덱스값을 통해 접근가능 5. a[0].nodeType(false) : a[0]은 '#'문자열이므로 DOM객체가 아니다. 그러므로 false
이를 종합해보면 false 가 되므로 jQuery.find(a,c)문이 실행된다.
jQuery.find
코드가 길기 때문에 잘라서 설명하도록 하겠습니다.jQuery.find(a, c) a = "#myDiv", c = undefined
[3~4] 두번째 인자인 context가 undefined 이기때문에 패스 [7] context 인자의 기본값을 설정함. 조건 두개를 먹어버리기에 document 로 설정된다. [9] t는 문자열 #myDiv이므로 String 이다. [11~] t 는 '/', '//' 을 포함하지 않은문자열이기 때문에 결과로 -1 이 나오므로 true 로 취급되나 부정 연산자가 붙어 false 참고로 결과로 true 가 되는경우는 문자열의 시작이 / 나 // 가 되어 0이 나왔을경우.
[5] jQuery.trim(t) 호출로 양 끝 공백문자 제거 후 replace()메서드 호출. 문자열 //로 시작되는 문자열에서 //를 제거한 문자열을 생성 [9] jQuery.token 에 있는 정규식을 정규표현식 객체 생성자인 RegExp를 이용해서 생성. [10] t 가 해당 정규식에 포함되었는지를 확인. 해당안되기에 false [12~] m 이 false 이기때문에 생략
정규식만 빠르게 확인하고 넘어갑니다. ^(\\.\\.|/\\.\\.) : .. 또는 /.. 로 시작되는 문자열 ^(>|/) : >나 / 로 시작되는 문자열 ^(\\+) : +로 ㅅ시작되는 문자열 ^(~) : ~로 시작되는 문자열
[2] t 가 , 이나 | 로 시작되는경우 true 가 되겠지만 t 는 #myDiv이므로 지나친다. [8-9] re2 에 정규표현식 리터럴으로 객체를생성하고 다음과같은 문자열패턴매칭을 수행한다. m[0] : #myDiv / m[1] : # / m[2] : myDiv [11] m[1]이 # 이므로 if문 이하 실행 [13] old = document.getElementById('myDiv'); [14] old 를 배열형태로 저장하여 old, ret, r 에 넣는다. [15] re2에 매칭되는부분들을 제거한 문자열을 생성해서 저장하라 t 는 re2 정규식에 매칭되므로 매칭된부분을 지우면 t는 빈 문자열이된다.
/^([#.]?)([a-z0-9\\*_-]*)/i ^ : 문자열시작 ([#.]?) : 문자클래스 []뒤에붙은 ? 는 없거나 한번반복되는 수량자를 의미한다. 그러므로 # | . 로 시작될경우 캡쳐 ([a-z0-9\\*_-]*) : 빈 문자열이나 문자클래스에 해당하는 문자들로 구성된 문자열 i : 정규표현식이 끝나고 나온 i 는 정규표현식 플래그. 대소문자를 구분하지않게된다.
[1] : t 는 빈 문자열이 되었기 때문에 실행되지않음 [8] : ret[0] 은 전에 id가 myDiv인 DOM객체를 넣었고 context는 document객체를 저장하였기 때문에 불일치. [9] : jQuery.merge는 두 배열을 합치는 jQuery의 유틸메서드이다. done은 ret 을 그대로 받음. ret 즉 myDiv DOM을 가르키는 변수를 결과값으로 리턴.
jQuery.find 메서드의 호출 결과가 this.get 메서드 호출의 인자로 사용된다.
[3] num은 DOM객체를 가진 배열 이므로 true가 된다. (find 에서 return 된 done) [7] this는 jQuery생성자로 만들어지는 객체. this를 유사배열객체로 만들기 위함. [8] 인자로 받은 num을 this에 넘긴다.
그럼 이제 다시 jQuery함수코드로 돌아가서
function jQuery(a, c) { ...... var fn = arguments[ arguments.length - 1 ]; if ( fn && fn.constructor == Function ) this.each(fn); }
[3] arguments[arguments.length -1 ]; 는 함수를 호출했을때 넘어온인자의 마지막인자. [5] c는 undefined, fn 은 c를 참조하므로 실행되지않는다. jQuery가 생성자로 호출되었기 때문에 id가 myDiv인 DOM객체를 포함한 jQuery 객체가 지금까지 살펴본 $(#myDiv)함수 호출의 최종결과가 된다.
이제 $("#myDiv").text() 를 살펴보자.[2] 지금 호출은 $("#myDiv").text()로 호출했기때문에 this 는 jQuery객체가된다. [4] e가 jQuery객체를 가르키기때문에 length가 1로 변경되어 실행된다. [5] e[0] 은 DOM 객체 myDiv 객체를 가르킨다. .childNodes e[0]의 자식 노드들을 담음. [6-9] for문든 자식노드 개수만큼 돈다. myDiv객체는 Hello라는 text노드 하나만을 자식노드로 가지고있기 때문에 한번만 실행되며 r[0]가 Dom객체를 가르키고 r[0].nodetype은 3이므로 변수 t 에는 hello문자열이 저장된다.
1 : 태그 2 : 속성 3 : 문자열 8 : 주석 9 : document
JavaScript 이벤트핸들러
<div id="clickDiv">Click Here</div> <script> $('#clickDiv').click(function() { alert('Mouse Click'); }) </script>해당 소스에서 자바스크립트가 어떻게 동작하는지 알아본다.
new function() { var e = ("blur,focus,load,resize,scroll,unload,click,dblclick," + "mousedown,mouseup,mousemove,mouseover,mouseout,change,reset,select," + "submit,keydown,keypress,keyup,error").split(","); for ( var i = 0; i < e.length; i++) new function() { var o = e[i]; jQuery.fn[o] = function(f) { return f ? this.bind(o, f) : this.trigger(o); }; }; };
이 코드를 통해서 jQuery의 프로토타입인 jQuery.fn 에 function(f) { return f ? this.bind(click, f) : this.trigger(click); }; 과 같은 함수가 추가된다
$('#clickDiv').click(function() { alert('Mouse Click'); })
click = functiond(f) { return f ? this.bind(click, f) : this.trigger(click); }이고 f 는 function() { alert('moust Click'); } 이 된다
each: function( obj, fn, args) { if ( obj.length == undefined ) for ( var i in obj ) fn.apply( obj[i], args || [i, obj[i]] ); else for ( var i = 0; i < obj.length; i++ ) fn.apply( obj[i], args || [i, obj[i]] ); return obj; },
if : 첫번재 인자인 obj 에 length 프로퍼티가 있는지 확인. 오브젝트가 배열이나 유사배열객체가 아닌지 판단한다. 첫번째 for : 인자가 배열이나 유사객체가 아닐때 실행된다. apply 메서드는 두번째 인자를 배열로받기때문에 [i, obj[i]]는 두개의 배열요소로 전달된다. 앞 코드가 for in 으로 되어있으므로 i 는 obj객체의 프로퍼티명, obj[i] 는 프로퍼티 값을 의미한다. 두번째 for : 인자가 배열이나 유사객체 일때 실행되므로 인덱스 순서대로 fn.apply가 실행된다. 결국 jQuery.each 메서드가 하는일은 전달받은 객체의 프로퍼티에 있는 각각의 함수를 실행하는 역할을 한다