SlideShare uma empresa Scribd logo
1 de 61
Baixar para ler offline
3
Functions are fundamental
Secrets of the JavaScript Ninja
• 왜 함수는 매우 중요한지
                 • 어떻게 함수는 first-class 객체인지
                 • 함수 내부의 컨텍스트
                 • variable argument lists 다루는법
                 • 함수를 위한 검사방법

왜 함수는 매우 중요한지
어떻게 함수는 first-class 객체인지
함수 내부의 컨텍스트
variable argument lists 다루는법
함수를 위한 검사방법
3.0 들어가며




  자바스크립트의 코드 품질 == 함수형 언어에 대한 인지




자바스크립트의 코드 품질 == 함수형 언어에 대한 인지
3.0 들어가며




            • 모든 함수는 first-class objects
            • 익명 함수



모든 함수 : first-class objects -> 모든 형태로 공존 가능
가장 중요한 특징 중 하나 : 익명 함수 -> 여러 장점을 가지게 된다
함수가 어떻게 정의되느냐? 이를 잘 이해해야 명확하고 간결하며 재사용 가능한 코드가 된다!!
3.1 함수 선언하기




       • Javascript에서는 함수를 선언하는 다양한
          방법이 있다.




3.1 함수 선언하기
Javascript에서는 함수를 선언하는 다양한 방법이 있다.
3.1 함수 선언하기


         // Listing 3.1 : http://jsbin.com/ahokod
         function isNimble(){ return true; }             //#1
         var canFly = function(){ return true; };        //#2
         window.isDeadly = function(){ return true; };   //#3

         console.log(window.isNimble);                   //#4
         console.log(window.canFly);                     //#4
         console.log(window.isDeadly);                   //#4




#1 함수명을 이용하여 선언 : named function (일반적으로 알고있는 방법)
#2 인라인의 익명 함수를 변수로 선언
#3 익명 함수를 window 객체의 속성으로 선언
3.1 함수 선언하기




3가지 정의는 전역 scope에서 본질적으로 동등 - 하지만 미묘한 차이가 있다.
순서를 바꿔보자
3.1 함수 선언하기


      // Listing 3.2 : http://jsbin.com/uyeneq
      var canFly = function() { return true; };
      window.isDeadly = function() { return true; };

      assert(isNimble() && canFly() && isDeadly(), //#2
             'Works, even though isNimble is declared below.'); //#2

      function isNimble() { return true; } //#3




isNimble() 함수가 assert() 뒤에 선언되었음에도 문제가 없다.
함수명을 이용해 선언한 경우 scope 내에서 어디든 접근 가능
3.1 함수 선언하기

            // Listing 3.3 : http://jsbin.com/itivom
            function stealthCheck(){
              assert(stealth(),                                             //#1
                     "We'll never get below the return, but that's OK!");
              return true;
              function stealth(){ return true; }                            //#2
            }
            stealthCheck();                                                 //#3




                네이밍 된 함수는 특별 권한을 가진다.




[Listing 3.3]

일반적인 실행 흐름 상 return 뒤에 선언 된 stealth() 까지 도달되지 않아보이지만..
이름지어진 함수는 특별 권한(specially privileged)
3.1 함수 선언하기


     // Listing 3.4 : http://jsbin.com/uyomix/2
     assert(typeof canFly == "undefined",                            //#A
            "canFly can't be forward referenced.");                  //#A
     assert(typeof isDeadly == "undefined", "Nor can isDeadly." );   //#A
     var canFly = function(){ return true; };                        //#B
     window.isDeadly = function(){ return true; };                   //#B




[Listing 3.4]
익명 함수는 앞에서 참조가 되지 않는다.
지금까지 본 개념은 네이밍, 흐름, 코드 내부 구조를 정하는 기초이며 매우 중요!
3.2 익명 함수



              • 이 개념은 functional language으로 부터
                   차용 된 매우 중요하고 논리적 개념

              • 일반적으로 나중에 사용 될 함수를
                   선언할 때 쓰인다.




3.2 익명 함수

이 개념은 functional language (Scheme 같은) 으로 부터 차용 된 매우 중요하고 논리적 개념
일반적으로 나중에 사용 될 함수를 선언할 때 쓰인다. (변수나 객체 속성으로 저장되거나, 콜백 같은)
3.2 익명 함수

                // Listing 3.5 : http://jsbin.com/ivejuq
                var obj = {
                   someMethod: function(){                            //#1
                     console.log('Hi!');                              //#1
                   }
                };

                obj.someMethod();                                     //#2

                setInterval(
                  function(){ console.log('Here!'); },                //#3
                1000);




[Listing 3.5]

#1 객체 속성으로 함수 선언
#2 속성을 통해 함수 호출
#3 함수 인자로 함수를 선언 : setInterval() 함수의 인자로 익명 함수 선언을 했으며 매 1초마다 호출된다.
3.2.1 재귀


                // Listing 3.6 : http://jsbin.com/iveduv
                function yell(n) {                                       //#1
                  return n > 0 ? yell(n-1) + "a" : "hiy";                //#1
                }                                                        //#1
                assert(yell(4) == "hiyaaaa",                             //#2
                       "Calling the named function comes naturally.");




                재귀를 위한 2가지 기준이 충족
                 1) 자기 자신을 참조하며
                 2) 종료조건으로 수렴




[Listing 3.6]

이 함수는 재귀를 위한 2가지 기준이 충족
1)자기 자신을 참조하며
2)종료조건으로 수렴 : n 인자는 줄어들며 0 보다 작아지면 재귀가 끝난다.
(조건2를 만족하지 않으면 무한 반복!)

named function 의 동작을 알아보았다. 그렇다면 익명 함수는?
3.2.1 재귀


                // Listing 3.7 : http://jsbin.com/ihuquv
                var ninja = {
                   yell: function(n) {                                  //#1
                     return n > 0 ? ninja.yell(n - 1) + "a" : "hiy";
                   }
                };
                assert(ninja.yell(4) == "hiyaaaa",
                        "An object property isn't too bad, either.");




[Listing 3.7]

객체 속성으로 익명 함수를 정의했으며, 재귀적으로 호출하기 위해 객체 속성을 참조하였다 : ninja.yell()
이 방법은 새로운 객체를 정의하기 전까지는 문제가 없다.
하지만 samurai 이름의 새 객체를 사용한다면?
3.2.1 재귀
           // Listing 3.8 : http://jsbin.com/ihuquv/2
           var ninja = {
              yell: function(n) {
                return n > 0 ? ninja.yell(n - 1) + "a" : "hiy";
              }
           };

           var samurai = { yell: ninja.yell };                     //#1

           ninja = {};                                             //#2

           try {
             assert(samurai.yell(4) == "hiyaaaa",                  //#3
                  "Is this going to work?");
           }
           catch(e) {
             console.log("Uh, this isn't good! Where'd ninja.yell go?");
           }


[Listing 3.8]
#2에서 ninja를 빈 객체로 정의하였고, 익명 함수는 여전히 존재 (samurai.yell 속성이 참조 중)
하지만 익명 함수 내부의 ninja.yell 속성은 더 이상 존재하지 않는다.
http://jsbin.com/ihuquv/3
위와 같이 함수 컨텍스트(this)를 수정하고, ninja 같이 명시적으로 익명 함수 참조하지 않는게 좋다.
다른 방식으로, 익명 함수에 이름을 부여하면 어떨까? 모순이 아닌가?
3.2.1 재귀

                // Listing 3.9 : http://jsbin.com/ihuquv/4
                var ninja = {
                   yell: function shout(n) {                      //#1
                     return n > 0 ? shout(n - 1) + "a" : "hiy";
                   }
                };

                assert(ninja.yell(4) == "hiyaaaa",                //#2
                       "Works as we would expect it to!");

                var samurai = { yell: ninja.yell };
                ninja = {};                                       //#3

                assert(samurai.yell(4) == "hiyaaaa",              //#4
                       "The method correctly calls itself.");




[Listing 3.9]

shout() 같이 인라인 함수에 이름이 부여할 수 있다는게 확인되었다.
겉으로 보기에 기괴할지 모르지만 다음과 같이 일반 변수에 할당도 가능하다.
3.2.1 재귀




             • 인라인 함수는 이름을 부여할 수 있다.
                  하지만,

             • 이 이름은 그 함수 자체에서만 볼 수 있다.


인라인 함수의 매우 중요한 포인트!
*인라인 함수는 이름을 부여할 수 있다. 하지만, 이 이름은 그 함수 자체에서만 볼 수 있다.*
3.2.1 재귀

     // Listing 3.10 : http://jsbin.com/opusuf
     var ninja = function myNinja(){                                 //#1
        assert(ninja == myNinja,                                     //#2
               "This function is named two things at once!");        //#2
     };

     ninja();                                                        //#3

     assert(typeof myNinja == "undefined",                           //#4
            "But myNinja isn't defined outside of the function.");   //#4




[Listing 3.10]
this를 사용하는 것보다 이 방법이 좀 더 명백한 접근을 보여준다.
또 다른 개념을 보자.
3.2.1 재귀

           // Listing 3.11 : http://jsbin.com/opusuf/2
           var ninja = {
              yell: function(n){
                return n > 0 ? arguments.callee(n-1) + "a" : "hiy";   //#1
              }
           };

           assert(ninja.yell(4) == "hiyaaaa",
                  "arguments.callee is the function itself.");




[Listing 3.11]
arguments.callee 속성은 함수를 호출한 대상(여기에선 자기 자신)을 알려준다.
3.2 익명 함수


          이런 여러가지 기법을 통해서 익명 함수는

                 • hard-coded 된 변수
                 • 속성 이름
          같은 깨지기 쉬운 의존성을 피해갈 수 있겠다.




이런 여러가지 기법을 통해서 익명 함수가 hard-coded 된 변수, 속성 이름 같은 깨지기 쉬운 의존성을 피해갈 수 있겠
다.
3.3 객체로서의 함수




              • 함수는 속성, 객체의 prototype을 가질 수
                    있고,

              • 변수나 속성으로 할당될 수 있다.


Javascript에서 함수는 속성, 객체의 prototype을 가질 수 있고, 변수나 속성으로 할당될 수 있다.
3.3 객체로서의 함수


             var obj = {};
             var fn = function(){};
             assert(obj && fn, "Both the object and function exist.");




           NOTE
           위와 같이 마지막에 세미콜론으로 마무리하는게 좋은 습관 
           특히 변수에 할당 이후엔 더욱!
           익명 함수도 예외는 아니다.




[예제코드]
객체를 변수에 할당할 수 있고, 함수도 마찬가지
NOTE : 위와 같이 마지막에 세미콜론으로 마무리하는게 좋은 습관
특히 변수에 할당 이후엔 더욱. 익명 함수도 예외는 아니다. 챕터???에서 다룰 코드압축에 도움이 된다.
3.3 객체로서의 함수


                 var obj = {};
                 var fn = function(){};
                 obj.prop = "hitsuke (distraction)";
                 fn.prop = "tanuki (climbing)";
                 assert(obj.prop && fn.prop,
                        "Both are objects, both have the property.");




           함수에도 속성 부여가 가능




다른 능력으로는 많은 사람이 놀랄법한 함수에 속성 부여!
[예제코드]
이런 함수의 모습은 라이브러리나 일반적인 on-page 코드를 통해 여러 방법으로 쓰일 수 있다.
3.3.1 함수 저장하기



            • 이벤트 콜백 관리는 함수 저장의 좋은 예제
            • 모든 함수를 배열에 넣어두고 루프를 돌며
                원하는 함수를 찾아내는 방법이 있지만,
                매우 비효율적




이벤트 콜백 관리는 함수 저장의 매우 명확한 예제
모든 함수를 배열에 넣어두고 루프를 돌며 중복 함수를 찾아내는 방법이 있지만, 매우 비효율적
3.3.1 함수 저장하기
                 // Listing 3.12 : http://jsbin.com/eqabag
                 var store = {
                    nextId: 1,                                //#1
                    cache: {},                                //#2
                    add: function(fn) {                       //#3
                      if (!fn.id) {                           //#3
                        fn.id = store.nextId++;               //#3
                        return !!(store.cache[fn.id] = fn);   //#3
                      }
                    }
                 };

                 function ninja(){}

                 assert(store.add(ninja),                     //#4
                        "Function was safely added.");        //#4
                 assert(!store.add(ninja),                    //#4
                        "But it was only added once.");       //#4



[Listing 3.12]
이 예제에서 만든 store 객체는 고유한 함수의 구성을 저장
#1 다음으로 설정 가능한 id 값
#2 함수를 캐시하여 저장하는 영역
#3 cache를 통하여 함수를 추가하는 add() 함수 : 성공 여부를 return
Tip : !! 문법은 다른 Javascript 표현식을 Boolean으로 변환하는 간단한 방법
3.3.2 Self-memoizing 함수




           • Memoization은 이전의 결과값을 기억할
                수 있게 함수를 만드는 과정




메모이제이션은 이전의 결과값을 기억할 수 있게 함수를 만드는 과정
소수를 구하는 간단한 예제를 살펴보자.
3.3.2 Self-memoizing 함수
       // Listing 3.13 : http://jsbin.com/arenaz
       function isPrime(value) {
         if (isPrime.answers[value] != null) {                  //#1
           return isPrime.answers[value];                       //#1
         }                                                      //#1
         var prime = value != 1; // 1 can never be prime
         for (var i = 2; i < value; i++) {
           if (value % i == 0) {
             prime = false;
             break;
           }
         }
         return isPrime.answers[value] = prime;                 //#2
       }

       isPrime.answers = {};                                    //#3

       assert(isPrime(5), "5 is prime!" );                      //#4
       assert(isPrime.answers[5], "The answer was cached!" );   //#4


[Listing 3.13]
#1 이미 캐시 된 값이 있다면 해당 값 return
#2 아니라면 계산 된 소수값을 저장
3.3.2 Self-memoizing 함수
      // http://jsbin.com/arenaz/2
      function isPrime(value) {
        if (!isPrime.anwers) isPrime.answers = {};
        if (isPrime.answers[value] != null) {                  //#1
          return isPrime.answers[value];                       //#1
        }                                                      //#1
        var prime = value != 1; // 1 can never be prime
        for (var i = 2; i < value; i++) {
          if (value % i == 0) {
            prime = false;
            break;
          }
        }
        return isPrime.answers[value] = prime;                 //#2
      }

      assert(isPrime(5), "5 is prime!" );                      //#4
      assert(isPrime.answers[5], "The answer was cached!" );   //#4




http://jsbin.com/arenaz/2
이와 같이 answers 속성 정의를 함수 초반에 해도 되겠다.
3.3.2 Self-memoizing 함수


              이런 방법의 장점 :

               • 이전의 계산 된 값을 활용함으로써 향
                      상 된 퍼포먼스

               • 특별한 추가 동작 없이 원할하게 동작
              단, 메모리를 희생하기 때문의 주의!




이런 방법의 장점 :
 이전의 계산 된 값을 활용함으로써 향상 된 퍼포먼스
 특별한 추가 동작 없이 원할하게 동작

단, 메모리를 희생하기 때문의 주의
3.3.2 Self-memoizing 함수

                  function getElements( name ) {
                    if (!getElements.cache) getElements.cache = {};
                    return getElements.cache[name] =
                      getElements.cache[name] ||
                      document.getElementsByTagName(name);
                  }




[또 다른 예제코드]
함수 속성으로 캐시를 하여 코드가 간단해지고, 더 복잡한 쿼리 프로세스를 거치지 않는다.
3.3.2 Self-memoizing 함수

                  function getElements( name ) {
                    if (!getElements.cache) getElements.cache = {};
                    return getElements.cache[name] =
                      getElements.cache[name] ||
                      document.getElementsByTagName(name);
                  }



                              Average               Min     Max            Deviation

           non-cached
                               12.58                12       13              0.50
             version

          cached version        1.73                 1        2              0.45

                                                          단위 ms, 1000회 반복, Firefox 3 결과




[또 다른 예제코드]
함수 속성으로 캐시를 하여 코드가 간단해지고, 더 복잡한 쿼리 프로세스를 거치지 않는다.
3.3.2 Self-memoizing 함수



               함수 속성의 유용성 :

                 • 한 공간에 캐시 정보를 저장/관리
                 • 즉, 추가 공간이나 캐시 객체가 필요 없다.


*함수 속성의 유용성*
  한 공간에 캐시 정보를 저장/관리. 즉, 추가 공간이나 캐시 객체가 필요 없다.
3.4 Context




              • 어마어마한 강점이자 해매이기쉬운 내용
              • this : 모든 함수 안에 존재



3.4 Context

어마어마한 강점이자 해매이기쉬운 내용
this : 모든 함수 안에 존재
3.4.1 함수 내부 Context

                    // Listing 3.14 : http://jsbin.com/uzucop
                    var katana = {
                       isSharp: true,                             //#1
                       use: function(){                           //#2
                         this.isSharp = !this.isSharp;            //#2
                       }                                          //#2
                    };

                    katana.use();                                 //#3

                    assert(!katana.isSharp,                       //#4
                           "The value of isSharp has been changed!");




3.4.1 함수 내부 Context
[Listing 3.14]
katana 객체 이름을 사용하여 직접적인 호출 없이 isSharp 속성에 접근
(만일 katana라는 객체 이름을 sword로 바꾼다면?)
3.4.2 독립적인 함수 내부 Context


                      // Listing 3.15 : http://jsbin.com/ukuwev
                      function katana(){                          //#1
                        this.isSharp = true;                      //#1
                      }                                           //#1

                      katana();                                   //#2

                      assert(isSharp === true,                    //#3
                             "A global property now exists.");




3.4.2 독립적인 함수 내부 Context
독립적(top-level)으로 사용될 경우는 어떨까?
[Listing 3.15]
전역 객체(window)에서 선언 된 경우 this 역시 window context 참조
이런 context 표현은 여러 상황에서 함수를 다룰 때 완전 중요하다.
3.4.2 독립적인 함수 내부 Context

                      // Listing 3.15 : http://jsbin.com/ukuwev
                      function katana(){                                                     //#1
                        this.isSharp = true;                                                 //#1
                      }                                                                      //#1

                      katana();                                                              //#2

                      assert(isSharp === true,                                               //#3
                             "A global property now exists.");




              NOTE
              ECMAScript 3.1 strict mode 에서는 객체 속성으로 함수 선언이 되지
              않은 경우 더 이상 전역 객체 context를 가지지 않는다.



3.4.2 독립적인 함수 내부 Context

Note : ECMAScript 3.1 strict mode 에서는 객체 속성으로 함수 선언이 되지 않은 경우 더 이상 전역 객체 context를 가지지 않는다.
3.4.3 Context 정의




             • Context는 함수를 어떻게 호출하느냐에
                  따라 결정할 수 있다.




3.4.3 Context 정의
함수의 context를 고유 기능이라 생각하지만, 현실은 그렇지 않다.
함수를 어떻게 호출하느냐에 따라 결정할 수 있다.
3.4.3 Context 정의


           call(), apply()

                  • 모든 함수에 존재
                  • 함수 호출에 이용 - context 정의
                  • 전달 인자 구체화

3.4.3 Context 정의
call(), apply()
모든 함수에 있으며, 함수 호출에 이용, context 정의, 전달 인자 구체화
3.4.3 Context 정의


                 // Listing 3.16 : http://jsbin.com/ibipeg
                 function fn(){ return this; }                                //#1

                 var ronin = {};                                              //#2

                 assert(fn() == this, "The context is the global object.");   //#3
                 assert(fn.call(ronin) == ronin,                              //#4
                        "The context is changed to a specific object." );




[Listing 3.16]

call() 함수의 첫번째 인자로 간단하게 context를 정의할 수 있다.
3.4.3 Context 정의

             // Listing 3.17 : http://jsbin.com/unesoq
             function add(a, b){                                //#1
               return a + b;                                    //#1
             }                                                  //#1

             assert(add.call(this, 1, 2) == 3,                   //#2
                    ".call() takes individual arguments" );

             assert(add.apply(this, [1, 2]) == 3,                //#3
                    ".apply() takes an array of arguments" );




            call : 각각 개별로 인자 전달
            apply : 배열형태로 인자 전달




call(), apply() 차이점 : 인자 전달 방법
[Listing 3.17]
call() : 각각 개별로 인자 전달
apply() : 배열형태로 인자 전달
이들의 실질적인 사용법을 간단한 예제로 알아보자.
3.4.4 반복문과 콜백



                •   직진하듯 진행하는 함수 호출이 필요할 때
                    직접 호출만으로 힘들다면, 콜백 함수를 이용

                •   함수의 참조를 다른 함수로 전달
                    → 다른 함수에선 이 참조를 이용해 콜백 호출

                •   대부분 javascript 라이브러리의 반복문에서 활용




3.4.4 반복문과 콜백

직진하듯 쭉 진행하는 함수 호출이 필요할 때, 직접 호출만으로 힘들다면, 콜백 함수를 이용
함수의 참조를 다른 함수로 전달 -> 다른 함수에선 이 참조를 이용해 콜백 호출
대부분 javascript 라이브러리의 반복문에서 활용
3.4.4 반복문과 콜백
          // Listing 3.18 : http://jsbin.com/elilix
          function loop(array,fn){                                //#1
            for (var i = 0; i < array.length; i++)                //#1
              if (fn.call(array, array[i], i) === false) break;   //#1
          }                                                       //#1

          var num = 0;                                            //#2
          var numbers = [4,5,6];                                  //#2

          loop(numbers, function(value, n){
            assert(this === numbers,                              //#3
                  "Context is correct.");
            assert(n == num++,                                    //#4
                  "Counter is as expected.");
            assert(value == numbers[n],                           //#5
                  "Value is as expected.");
          });



[Listing 3.18]
기존의 for 반복문에 비해 유연함
콜백은 인스턴스 생성 없이 동작하며, this context로 언제든 원래 배열에 접근 가능
3.4.4 반복문과 콜백




             • 라이브러리에선 정말 중요한 요소
             • 비동기적,Ajax 응답 반응, 배열에서 검색)
               (버튼 클릭,
                       비결정적 행동




라이브러리에선 정말 중요한 요소
비동기적, 비결정적 행동 (버튼 클릭, Ajax 응답 반응, 배열에서 검색)
3.4.5 배열 메서드 속이기



         배열과 유사한 객체를 생성했다면,

         ➡ 배열과 유사하게 동작하지만 실질적으
                로 배열의 추가 기능은 가지지 못한다.




3.4.5 배열 메서드 속이기
배열과 유사한 객체를 생성했다면, 배열과 유사하게 동작하지만 실질적으로 배열의 추가 기능은 가지지 못한다.
해결책으로 새 객체를 생성할 때 마다 새로운 배열도 생성하고 따라서 필요한 속성과 메서드를 만든다.
하지만 매우 느림
일반 객체에 우리가 필요한 기능이 적용가능한지 실험해보자.
3.4.5 배열 메서드 속이기
         // Listing 3.19 : http://jsbin.com/utibam/2
         var elems = {
            length: 0,                                                        //#1
            add: function(elem){                                              //#2
               Array.prototype.push.call(this, elem);
            },
            find: function(id){                                               //#3
               this.add(document.getElementById(id));
            }
         };

         elems.find("first");                                                 //#4
         assert(elems.length == 1 && elems[0].nodeType,                       //#4
                "Verify that we have an element in our stash");               //#4

         elems.find("second");                                                //#4
         assert(elems.length == 2 && elems[1].nodeType,                       //#4
                "Verify the other insertion");                                //#4



(우선, 코드에서 div#first, div#second DOM노드를 가지고 있다고 가정)
add() 함수에서 네이티브 객체 메서드(Array.prototype.push) 사용
보통 이 함수는 배열 context 연산에 사용되지만 여기선 call() 메서드를 사용해 객체 context를 넘겨 마치 배열인양 동작
length 속성도 증가됨!
이런 틀을 무너뜨리는 예시는 유순한 함수 context 위력을 보여준다.
3.5 Variable-length 인자 리스트




3.5 Variable-length 인자 리스트

유연하여 강력한 함수 인자의 특징을 살펴보자.
3.5.1 배열에서 최소/최대 숫자


              • 기본적인 기능이 아니라서 직접 정의해
                      보자.

              • 단순히 반복문으로 배열을 탐색하는 방
                      법이 아닌 다른 방법으로.

              • Math.min(),    Math.max() 메서드는
                      인자 갯수 상관없이 처리 가능



3.5.1 배열에서 최소/최대 숫자

Javascript 언어에서 기본적으로 정의되어 있지 않기 때문에 직접 만들어보자.
반복문으로 배열을 탐색하는 방법이 있지만 다른 방법으로.
Math.min(), Math.max() 메서드는 인자 갯수 상관없이 처리 가능
3.5.1 배열에서 최소/최대 숫자

                   // Listing 3.20 : http://jsbin.com/uxipot
                   function smallest(array){                                        //#1
                     return Math.min.apply(Math, array);                            //#1
                   }                                                                //#1

                   function largest(array){                                         //#2
                     return Math.max.apply(Math, array);                            //#2
                   }                                                                //#2

                   assert(smallest([0, 1, 2, 3]) == 0,                              //#3
                          "Located the smallest value.");                           //#3
                   assert(largest([0, 1, 2, 3]) == 3,                               //#3
                          "Located the largest value.");                            //#3




[Listing 3.20]

apply() 호출할 때 context는 Math 객체로 지정. 상관없이 min(), max() 동작은 하지만 깔끔한 context 유지를 위해.
3.5.2 함수 오버로딩




3.5.2 함수 오버로딩

앞의 3.2절에서 보았던 arguments 변수에 대해 자세히 살펴보자.
Detecting and Traversing Arguments
        // Listing 3.21 : http://jsbin.com/ereseg
        function merge(root){                            //#1
          for (var i = 1; i < arguments.length; i++) {
            for (var key in arguments[i]) {
              root[key] = arguments[i][key];
            }
          }
          return root;
        }

        var merged = merge(                              //#2
          {name: "Batou"},                               //#2
          {city: "Niihama"});                            //#2

        assert(merged.name == "Batou",                   //#3
               "The original name is intact.");          //#3
        assert(merged.city == "Niihama",                 //#3
               "And the city has been copied over.");    //#3



* Detecting and Traversing Arguments
하나의 root 객체에 다중 객체를 병합
[Listing 3.21]
가능한 하나의 전달받은 인자(root)는 이름으로 참조할 수 있도록.
추가로 전달 받는 인자는 arguments 변수를 통하여.
Tip : 전달된 인자가 있는지 확인하는 방법 : 인자이름 === undefined
Slicing and Dicing an Arguments List


       // Listing 3.22 : http://jsbin.com/iwacod
       function multiMax(multi){
         return multi * Math.max.apply(Math, arguments.slice(1));
       }

       assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)");




* Slicing and Dicing an Arguments List
첫번째 인자와 나머지 인자 중 최대값을 곱하는 함수
[Listing 3.22]
뭔일이여?
arguments 변수는 실제 배열이 아니다.
Slicing and Dicing an Arguments List


      // Listing 3.22 : http://jsbin.com/iwacod
      function multiMax(multi){
        return multi * Math.max.apply(Math, arguments.slice(1));
      }

      assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)");




             arguments는 실제 배열이 아니다.




뭔일이여?
arguments 변수는 실제 배열이 아니다.
3.5.2 함수 오버로딩


                 // Listing 3.23 : http://jsbin.com/iwacod/2
                 function multiMax(multi){
                   return multi * Math.max.apply(Math,
                     Array.prototype.slice.call(arguments, 1));   //#1
                 }

                 assert(multiMax(3, 1, 2, 3) == 9,
                        "3*3=9 (First arg, by largest.)");




[Listing 3.23]

앞서 봤던 배열 prototype 방식으로 해결
3.5.3 함수 오버로딩




                • 겉으로 보기엔 같은 이름의 함수이지만
                 서로 다른 동작을 하는 형태




3.5.3 함수 오버로딩

겉으로 보기엔 같은 이름의 함수이지만 서로 다른 동작을 하는 형태에 대해 보자.
The Function's Length Property


      function makeNinja(name){}
      function makeSamurai(name, rank){}
      assert( makeNinja.length == 1, "Only expecting a single argument" );
      assert( makeSamurai.length == 2, "Two arguments expected" );




              length : 함수 선언에서 명명 된 인자의 갯수
              arguments.length : 실제로 전달 받은 인자의 갯수




* The Function's Length Property
잘 알려지지 않았지만 모든 함수엔 length 속성이 있다.
http://jsbin.com/ubacul
   length : 함수 선언에서 명명 된 인자의 갯수
   arguments.length : 실제로 전달 받은 인자의 갯수
Overloading Functions By Argument Count

      // Listing 3.24 : http://jsbin.com/ayuher
      function addMethod(object, name, fn) {
        var old = object[name];                   //#1
        object[name] = function(){
           if (fn.length == arguments.length)     //#2
             return fn.apply(this, arguments)     //#2
           else if (typeof old == 'function')     //#3
             return old.apply(this, arguments);   //#3
        };
      }




* Overloading Functions By Argument Count
몇개의 인자를 전달받느냐에 따라 서로 다르게 동작
if-then-else-if 명세
Overloading Functions By Argument Count

      // Listing 3.24 : http://jsbin.com/ayuher
      function addMethod(object, name, fn) {
        var old = object[name];                                           //#1
        object[name] = function(){
           if (fn.length == arguments.length)                             //#2
             return fn.apply(this, arguments)                             //#2
           else if (typeof old == 'function')                             //#3
             return old.apply(this, arguments);                           //#3
        };
      }


      addMethod(myObject,'whatever',function(){ /* do something */ });

      addMethod(myObject,'whatever',function(p1){ /* do something else */ });




addMethod(myObject,'whatever',function(){ /* do something */ });
myObject.whatever 속성에 익명 함수를 적용
addMethod(myObject,'whatever',function(p1){ /* do something else */ });
이 때 같은 myObject.whatever()를 호출해도 서로 다른 익명 함수가 호출된다.
--
#1 이미 name 속성으로 선언된 내용이 있다면 old 변수에 저장된다. - 클로져
object.name() 함수가 실행 되었을때,
#2 최근에 전달 받았던 fn 인자의 갯수와 동일 하다면 바로 fn 익명 함수를 실행
#3 위의 인자 갯수와 다르다고, old에 저장 된 함수가 있다면 해당 함수를 실행
(#3)부분이 매우 어려운듯
// Listing 3.25 : http://jsbin.com/ayuher

   Overloading Functions By Argument Count
                             var ninjas = {
                                values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"]
                                                                                             //#1

                             };

                             addMethod(ninjas, "find", function(){                           //#2
                               return this.values;
                             });
    // Listing 3.24 : http://jsbin.com/ayuher
    function addMethod(object, name, fn) function(name){
                       addMethod(ninjas, "find", {                                           //#3
      var old = object[name]; =i[];0; i < this.values.length; i++)
                         var ret
                                                                  //#1
                         for (var    =
      object[name] = function(){
                           if (this.values[i].indexOf(name) == 0)
                             ret.push(this.values[i]);
         if (fn.length == arguments.length)                       //#2
                         return ret;
           return fn.apply(this, arguments)
                       });                                        //#2
         else if (typeof old == 'function')                       //#3
                       addMethod(ninjas, "find", function(first, last){                      //#4
           return old.apply(this, arguments);
                         var ret = [];                            //#3
      };                 for (var i = 0; i < this.values.length; i++)
                           if (this.values[i] == (first + " " + last))
    }                        ret.push(this.values[i]);
                               return ret;
                             });

    addMethod(myObject,'whatever',function(){ /* do something */ });
                      assert(ninjas.find().length == 3,                                      //#5
                             "Found all ninjas");
    addMethod(myObject,'whatever',function(p1){ /* do something
                      assert(ninjas.find("Sam").length == 1,                           else */ });
                             "Found ninja by first name");
                      assert(ninjas.find("Dean", "Edwards").length == 1,
                             "Found ninja by first and last name");
                      assert(ninjas.find("Alex", "X", "Russell") == null,
                             "Found nothing");


[Listing 3.25]
각 인자의 갯수마다 다르게 처리되는 모습을 볼 수 있다. (오버로딩처럼 보임)
제약사항 :
    오직 인자의 갯수에 따라 판단
    오버로딩 된 함수는 호출에 부하가 있다.
3.6 함수 체크


                   •       Firefox 2, 3 : HTML 객체 엘리먼트를 typeof로 확인하면 잘못 된
                           "function" 결과

                   •       Firefox 2 : 정규식을 함수처럼 호출 가능. /test/("a test") 하
                           지만 Firefox 2에서는 잘못 된 "function" 결과

                   •       IE : iframe 같이 다른 윈도우 영역에서 타입을 찾으려하면
                                'unknown' 결과

                   •       Safari : DOM Nodelist가 "function" 타입으로 인식
                                    typeof document.body.childNodes == "function"




3.6 함수 체크
typeof 활용하여 함수 타입을 확인
- Firefox 2, 3 : HTML 객체 엘리먼트를 typeof로 확인하면 잘못 된 "function" 결과
- Firefox 2 : 정규식을 함수처럼 호출 가능. /test/("a test") 하지만 Firefox 2에서는 잘못 된 "function" 결과
- IE : iframe 같이 다른 윈도우 영역에서 타입을 찾으려하면 'unknown' 결과
- Safari : DOM Nodelist가 "function" 타입으로 인식: typeof document.body.childNodes == "function"
3.6 함수 체크




       function isFunction(fn) {
         return Object.prototype.toString.call(fn) === "[object Function]";
       }




해결책으로 Object.prototype.toString 활용
3.7 요약

               •    함수가 동작하는 다양한 방법을 보았다.

               •    함수 내부 동작에 이해가 근본적으로 높은 품질의 코드를 생성

               •    함수를 정의하는 여러 기술과 각각의 이점

               •    익명 함수와 재귀에서 arguments.callee 사용으로 문제 해결

               •    함수를 객체와 같이 사용하여 추가적인 데이터 저장의 이점

               •    함수에서 context 동작과 apply, call 사용으로 스스로 조작하는 방법

               •    여러 형태의 인자에 대해 처리할 수 있는 함수 (그리고 오버로딩)

               •    마무리로 객체 타입과 함수 타입에 관한 크로스 브라우징 이슈




3.7 Summary

Javascript에서 함수가 동작하는 다양한 방법을 보았다.
함수 내부 동작에 이해가 근본적으로 높은 품질의 코드를 생성
함수를 정의하는 여러 기술과 각각의 이점
익명 함수와 재귀에서 arguments.callee 사용으로 문제 해결
함수를 객체와 같이 사용하여 추가적인 데이터 저장의 이점
함수에서 context 동작과 apply, call 사용으로 스스로 조작하는 방법
여러 형태의 인자에 대해 처리할 수 있는 함수 (그리고 오버로딩)
마무리로 객체 타입과 함수 타입에 관한 크로스 브라우징 이슈

Mais conteúdo relacionado

Mais procurados

자바스크립트 함수
자바스크립트 함수자바스크립트 함수
자바스크립트 함수
유진 변
 
파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기
Yong Joon Moon
 

Mais procurados (20)

파이썬 namespace Binding 이해하기
파이썬 namespace Binding 이해하기 파이썬 namespace Binding 이해하기
파이썬 namespace Binding 이해하기
 
Swift3 subscript inheritance initialization
Swift3 subscript inheritance initializationSwift3 subscript inheritance initialization
Swift3 subscript inheritance initialization
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료
 
자바스크립트 함수
자바스크립트 함수자바스크립트 함수
자바스크립트 함수
 
Jupyter notebook 이해하기
Jupyter notebook 이해하기 Jupyter notebook 이해하기
Jupyter notebook 이해하기
 
파이썬 iterator generator 이해하기
파이썬 iterator generator 이해하기파이썬 iterator generator 이해하기
파이썬 iterator generator 이해하기
 
파이썬정리 20160130
파이썬정리 20160130파이썬정리 20160130
파이썬정리 20160130
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop
 
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
이것이 자바다 Chap.11 기본 API 클래스(java)(KOR)
 
파이썬 class 및 function namespace 이해하기
파이썬 class 및 function namespace 이해하기파이썬 class 및 function namespace 이해하기
파이썬 class 및 function namespace 이해하기
 
Scala type class pattern
Scala type class patternScala type class pattern
Scala type class pattern
 
Java 변수자료형
Java 변수자료형Java 변수자료형
Java 변수자료형
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
 
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
스파르탄스터디 E04 Javascript 객체지향, 함수형 프로그래밍
 
파이썬 병렬프로그래밍
파이썬 병렬프로그래밍파이썬 병렬프로그래밍
파이썬 병렬프로그래밍
 
프론트엔드스터디 E03 - Javascript intro.
프론트엔드스터디 E03 - Javascript intro.프론트엔드스터디 E03 - Javascript intro.
프론트엔드스터디 E03 - Javascript intro.
 
파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기파이썬 반복자 생성자 이해하기
파이썬 반복자 생성자 이해하기
 
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
이것이 자바다 Chap. 6 클래스(CLASS)(KOR)
 
Swift3 generic
Swift3 genericSwift3 generic
Swift3 generic
 
프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function
 

Destaque

The mikado method xp days ukraine
The mikado method   xp days ukraineThe mikado method   xp days ukraine
The mikado method xp days ukraine
ellnestam
 
Ciklum net sat12112011-vladimir gorshunov -scrum and kanban in action
Ciklum net sat12112011-vladimir gorshunov -scrum and kanban in actionCiklum net sat12112011-vladimir gorshunov -scrum and kanban in action
Ciklum net sat12112011-vladimir gorshunov -scrum and kanban in action
Ciklum Ukraine
 

Destaque (9)

Single Page web Application
Single Page web ApplicationSingle Page web Application
Single Page web Application
 
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modificationSecrets of the JavaScript Ninja - Chapter 12. DOM modification
Secrets of the JavaScript Ninja - Chapter 12. DOM modification
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
 
Single page webapplications
Single page webapplicationsSingle page webapplications
Single page webapplications
 
Scala in Action - Heiko Seeburger
Scala in Action - Heiko SeeburgerScala in Action - Heiko Seeburger
Scala in Action - Heiko Seeburger
 
node.js in action
node.js in actionnode.js in action
node.js in action
 
The mikado method xp days ukraine
The mikado method   xp days ukraineThe mikado method   xp days ukraine
The mikado method xp days ukraine
 
Building Single-page Web Applications with AngularJS @ TechCamp Sai Gon 2014
Building Single-page Web Applications with AngularJS @ TechCamp Sai Gon 2014Building Single-page Web Applications with AngularJS @ TechCamp Sai Gon 2014
Building Single-page Web Applications with AngularJS @ TechCamp Sai Gon 2014
 
Ciklum net sat12112011-vladimir gorshunov -scrum and kanban in action
Ciklum net sat12112011-vladimir gorshunov -scrum and kanban in actionCiklum net sat12112011-vladimir gorshunov -scrum and kanban in action
Ciklum net sat12112011-vladimir gorshunov -scrum and kanban in action
 

Semelhante a Secrets of the JavaScript Ninja - Chapter 3. Functions are Fundamental

파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304
Yong Joon Moon
 
자바스크립트 패턴 3장
자바스크립트 패턴 3장자바스크립트 패턴 3장
자바스크립트 패턴 3장
Software in Life
 
Jdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamicJdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamic
knight1128
 
Learning Node Book, Chapter 5
Learning Node Book, Chapter 5Learning Node Book, Chapter 5
Learning Node Book, Chapter 5
Ji Hun Kim
 

Semelhante a Secrets of the JavaScript Ninja - Chapter 3. Functions are Fundamental (20)

헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리헷갈리는 자바스크립트 정리
헷갈리는 자바스크립트 정리
 
파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304파이썬+주요+용어+정리 20160304
파이썬+주요+용어+정리 20160304
 
파이썬+함수이해하기 20160229
파이썬+함수이해하기 20160229파이썬+함수이해하기 20160229
파이썬+함수이해하기 20160229
 
Javascript - Function
Javascript - FunctionJavascript - Function
Javascript - Function
 
Javascript 함수(function) 개념, 호출패턴, this, prototype, scope
Javascript 함수(function) 개념, 호출패턴, this, prototype, scopeJavascript 함수(function) 개념, 호출패턴, this, prototype, scope
Javascript 함수(function) 개념, 호출패턴, this, prototype, scope
 
Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저
 
스칼라와 스파크 영혼의 듀오
스칼라와 스파크 영혼의 듀오스칼라와 스파크 영혼의 듀오
스칼라와 스파크 영혼의 듀오
 
[ES6] 9. Iterator
[ES6] 9. Iterator[ES6] 9. Iterator
[ES6] 9. Iterator
 
게임프로그래밍입문 7
게임프로그래밍입문 7게임프로그래밍입문 7
게임프로그래밍입문 7
 
Start IoT with JavaScript - 6.함수
Start IoT with JavaScript - 6.함수Start IoT with JavaScript - 6.함수
Start IoT with JavaScript - 6.함수
 
Javascript
JavascriptJavascript
Javascript
 
자바스크립트 패턴 3장
자바스크립트 패턴 3장자바스크립트 패턴 3장
자바스크립트 패턴 3장
 
JavaScript Patterns - Chapter 3. Literals and Constructors
JavaScript Patterns - Chapter 3. Literals and ConstructorsJavaScript Patterns - Chapter 3. Literals and Constructors
JavaScript Patterns - Chapter 3. Literals and Constructors
 
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
Javascript 실행 가능한 코드(Executable Code)와 실행 콘텍스트(Execution Context), Lexical En...
 
7가지 동시성 모델 4장
7가지 동시성 모델 4장7가지 동시성 모델 4장
7가지 동시성 모델 4장
 
Xe hack
Xe hackXe hack
Xe hack
 
파이썬 심화
파이썬 심화파이썬 심화
파이썬 심화
 
Jdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamicJdk(java) 7 - 5. invoke-dynamic
Jdk(java) 7 - 5. invoke-dynamic
 
Multithread programming 20151206_서진택
Multithread programming 20151206_서진택Multithread programming 20151206_서진택
Multithread programming 20151206_서진택
 
Learning Node Book, Chapter 5
Learning Node Book, Chapter 5Learning Node Book, Chapter 5
Learning Node Book, Chapter 5
 

Secrets of the JavaScript Ninja - Chapter 3. Functions are Fundamental

  • 1. 3 Functions are fundamental Secrets of the JavaScript Ninja
  • 2. • 왜 함수는 매우 중요한지 • 어떻게 함수는 first-class 객체인지 • 함수 내부의 컨텍스트 • variable argument lists 다루는법 • 함수를 위한 검사방법 왜 함수는 매우 중요한지 어떻게 함수는 first-class 객체인지 함수 내부의 컨텍스트 variable argument lists 다루는법 함수를 위한 검사방법
  • 3. 3.0 들어가며 자바스크립트의 코드 품질 == 함수형 언어에 대한 인지 자바스크립트의 코드 품질 == 함수형 언어에 대한 인지
  • 4. 3.0 들어가며 • 모든 함수는 first-class objects • 익명 함수 모든 함수 : first-class objects -> 모든 형태로 공존 가능 가장 중요한 특징 중 하나 : 익명 함수 -> 여러 장점을 가지게 된다 함수가 어떻게 정의되느냐? 이를 잘 이해해야 명확하고 간결하며 재사용 가능한 코드가 된다!!
  • 5. 3.1 함수 선언하기 • Javascript에서는 함수를 선언하는 다양한 방법이 있다. 3.1 함수 선언하기 Javascript에서는 함수를 선언하는 다양한 방법이 있다.
  • 6. 3.1 함수 선언하기 // Listing 3.1 : http://jsbin.com/ahokod function isNimble(){ return true; } //#1 var canFly = function(){ return true; }; //#2 window.isDeadly = function(){ return true; }; //#3 console.log(window.isNimble); //#4 console.log(window.canFly); //#4 console.log(window.isDeadly); //#4 #1 함수명을 이용하여 선언 : named function (일반적으로 알고있는 방법) #2 인라인의 익명 함수를 변수로 선언 #3 익명 함수를 window 객체의 속성으로 선언
  • 7. 3.1 함수 선언하기 3가지 정의는 전역 scope에서 본질적으로 동등 - 하지만 미묘한 차이가 있다. 순서를 바꿔보자
  • 8. 3.1 함수 선언하기 // Listing 3.2 : http://jsbin.com/uyeneq var canFly = function() { return true; }; window.isDeadly = function() { return true; }; assert(isNimble() && canFly() && isDeadly(), //#2 'Works, even though isNimble is declared below.'); //#2 function isNimble() { return true; } //#3 isNimble() 함수가 assert() 뒤에 선언되었음에도 문제가 없다. 함수명을 이용해 선언한 경우 scope 내에서 어디든 접근 가능
  • 9. 3.1 함수 선언하기 // Listing 3.3 : http://jsbin.com/itivom function stealthCheck(){ assert(stealth(), //#1 "We'll never get below the return, but that's OK!"); return true; function stealth(){ return true; } //#2 } stealthCheck(); //#3 네이밍 된 함수는 특별 권한을 가진다. [Listing 3.3] 일반적인 실행 흐름 상 return 뒤에 선언 된 stealth() 까지 도달되지 않아보이지만.. 이름지어진 함수는 특별 권한(specially privileged)
  • 10. 3.1 함수 선언하기 // Listing 3.4 : http://jsbin.com/uyomix/2 assert(typeof canFly == "undefined", //#A "canFly can't be forward referenced."); //#A assert(typeof isDeadly == "undefined", "Nor can isDeadly." ); //#A var canFly = function(){ return true; }; //#B window.isDeadly = function(){ return true; }; //#B [Listing 3.4] 익명 함수는 앞에서 참조가 되지 않는다. 지금까지 본 개념은 네이밍, 흐름, 코드 내부 구조를 정하는 기초이며 매우 중요!
  • 11. 3.2 익명 함수 • 이 개념은 functional language으로 부터 차용 된 매우 중요하고 논리적 개념 • 일반적으로 나중에 사용 될 함수를 선언할 때 쓰인다. 3.2 익명 함수 이 개념은 functional language (Scheme 같은) 으로 부터 차용 된 매우 중요하고 논리적 개념 일반적으로 나중에 사용 될 함수를 선언할 때 쓰인다. (변수나 객체 속성으로 저장되거나, 콜백 같은)
  • 12. 3.2 익명 함수 // Listing 3.5 : http://jsbin.com/ivejuq var obj = { someMethod: function(){ //#1 console.log('Hi!'); //#1 } }; obj.someMethod(); //#2 setInterval( function(){ console.log('Here!'); }, //#3 1000); [Listing 3.5] #1 객체 속성으로 함수 선언 #2 속성을 통해 함수 호출 #3 함수 인자로 함수를 선언 : setInterval() 함수의 인자로 익명 함수 선언을 했으며 매 1초마다 호출된다.
  • 13. 3.2.1 재귀 // Listing 3.6 : http://jsbin.com/iveduv function yell(n) { //#1 return n > 0 ? yell(n-1) + "a" : "hiy"; //#1 } //#1 assert(yell(4) == "hiyaaaa", //#2 "Calling the named function comes naturally."); 재귀를 위한 2가지 기준이 충족 1) 자기 자신을 참조하며 2) 종료조건으로 수렴 [Listing 3.6] 이 함수는 재귀를 위한 2가지 기준이 충족 1)자기 자신을 참조하며 2)종료조건으로 수렴 : n 인자는 줄어들며 0 보다 작아지면 재귀가 끝난다. (조건2를 만족하지 않으면 무한 반복!) named function 의 동작을 알아보았다. 그렇다면 익명 함수는?
  • 14. 3.2.1 재귀 // Listing 3.7 : http://jsbin.com/ihuquv var ninja = { yell: function(n) { //#1 return n > 0 ? ninja.yell(n - 1) + "a" : "hiy"; } }; assert(ninja.yell(4) == "hiyaaaa", "An object property isn't too bad, either."); [Listing 3.7] 객체 속성으로 익명 함수를 정의했으며, 재귀적으로 호출하기 위해 객체 속성을 참조하였다 : ninja.yell() 이 방법은 새로운 객체를 정의하기 전까지는 문제가 없다. 하지만 samurai 이름의 새 객체를 사용한다면?
  • 15. 3.2.1 재귀 // Listing 3.8 : http://jsbin.com/ihuquv/2 var ninja = { yell: function(n) { return n > 0 ? ninja.yell(n - 1) + "a" : "hiy"; } }; var samurai = { yell: ninja.yell }; //#1 ninja = {}; //#2 try { assert(samurai.yell(4) == "hiyaaaa", //#3 "Is this going to work?"); } catch(e) { console.log("Uh, this isn't good! Where'd ninja.yell go?"); } [Listing 3.8] #2에서 ninja를 빈 객체로 정의하였고, 익명 함수는 여전히 존재 (samurai.yell 속성이 참조 중) 하지만 익명 함수 내부의 ninja.yell 속성은 더 이상 존재하지 않는다. http://jsbin.com/ihuquv/3 위와 같이 함수 컨텍스트(this)를 수정하고, ninja 같이 명시적으로 익명 함수 참조하지 않는게 좋다. 다른 방식으로, 익명 함수에 이름을 부여하면 어떨까? 모순이 아닌가?
  • 16. 3.2.1 재귀 // Listing 3.9 : http://jsbin.com/ihuquv/4 var ninja = { yell: function shout(n) { //#1 return n > 0 ? shout(n - 1) + "a" : "hiy"; } }; assert(ninja.yell(4) == "hiyaaaa", //#2 "Works as we would expect it to!"); var samurai = { yell: ninja.yell }; ninja = {}; //#3 assert(samurai.yell(4) == "hiyaaaa", //#4 "The method correctly calls itself."); [Listing 3.9] shout() 같이 인라인 함수에 이름이 부여할 수 있다는게 확인되었다. 겉으로 보기에 기괴할지 모르지만 다음과 같이 일반 변수에 할당도 가능하다.
  • 17. 3.2.1 재귀 • 인라인 함수는 이름을 부여할 수 있다. 하지만, • 이 이름은 그 함수 자체에서만 볼 수 있다. 인라인 함수의 매우 중요한 포인트! *인라인 함수는 이름을 부여할 수 있다. 하지만, 이 이름은 그 함수 자체에서만 볼 수 있다.*
  • 18. 3.2.1 재귀 // Listing 3.10 : http://jsbin.com/opusuf var ninja = function myNinja(){ //#1 assert(ninja == myNinja, //#2 "This function is named two things at once!"); //#2 }; ninja(); //#3 assert(typeof myNinja == "undefined", //#4 "But myNinja isn't defined outside of the function."); //#4 [Listing 3.10] this를 사용하는 것보다 이 방법이 좀 더 명백한 접근을 보여준다. 또 다른 개념을 보자.
  • 19. 3.2.1 재귀 // Listing 3.11 : http://jsbin.com/opusuf/2 var ninja = { yell: function(n){ return n > 0 ? arguments.callee(n-1) + "a" : "hiy"; //#1 } }; assert(ninja.yell(4) == "hiyaaaa", "arguments.callee is the function itself."); [Listing 3.11] arguments.callee 속성은 함수를 호출한 대상(여기에선 자기 자신)을 알려준다.
  • 20. 3.2 익명 함수 이런 여러가지 기법을 통해서 익명 함수는 • hard-coded 된 변수 • 속성 이름 같은 깨지기 쉬운 의존성을 피해갈 수 있겠다. 이런 여러가지 기법을 통해서 익명 함수가 hard-coded 된 변수, 속성 이름 같은 깨지기 쉬운 의존성을 피해갈 수 있겠 다.
  • 21. 3.3 객체로서의 함수 • 함수는 속성, 객체의 prototype을 가질 수 있고, • 변수나 속성으로 할당될 수 있다. Javascript에서 함수는 속성, 객체의 prototype을 가질 수 있고, 변수나 속성으로 할당될 수 있다.
  • 22. 3.3 객체로서의 함수 var obj = {}; var fn = function(){}; assert(obj && fn, "Both the object and function exist."); NOTE 위와 같이 마지막에 세미콜론으로 마무리하는게 좋은 습관  특히 변수에 할당 이후엔 더욱! 익명 함수도 예외는 아니다. [예제코드] 객체를 변수에 할당할 수 있고, 함수도 마찬가지 NOTE : 위와 같이 마지막에 세미콜론으로 마무리하는게 좋은 습관 특히 변수에 할당 이후엔 더욱. 익명 함수도 예외는 아니다. 챕터???에서 다룰 코드압축에 도움이 된다.
  • 23. 3.3 객체로서의 함수 var obj = {}; var fn = function(){}; obj.prop = "hitsuke (distraction)"; fn.prop = "tanuki (climbing)"; assert(obj.prop && fn.prop, "Both are objects, both have the property."); 함수에도 속성 부여가 가능 다른 능력으로는 많은 사람이 놀랄법한 함수에 속성 부여! [예제코드] 이런 함수의 모습은 라이브러리나 일반적인 on-page 코드를 통해 여러 방법으로 쓰일 수 있다.
  • 24. 3.3.1 함수 저장하기 • 이벤트 콜백 관리는 함수 저장의 좋은 예제 • 모든 함수를 배열에 넣어두고 루프를 돌며 원하는 함수를 찾아내는 방법이 있지만, 매우 비효율적 이벤트 콜백 관리는 함수 저장의 매우 명확한 예제 모든 함수를 배열에 넣어두고 루프를 돌며 중복 함수를 찾아내는 방법이 있지만, 매우 비효율적
  • 25. 3.3.1 함수 저장하기 // Listing 3.12 : http://jsbin.com/eqabag var store = { nextId: 1, //#1 cache: {}, //#2 add: function(fn) { //#3 if (!fn.id) { //#3 fn.id = store.nextId++; //#3 return !!(store.cache[fn.id] = fn); //#3 } } }; function ninja(){} assert(store.add(ninja), //#4 "Function was safely added."); //#4 assert(!store.add(ninja), //#4 "But it was only added once."); //#4 [Listing 3.12] 이 예제에서 만든 store 객체는 고유한 함수의 구성을 저장 #1 다음으로 설정 가능한 id 값 #2 함수를 캐시하여 저장하는 영역 #3 cache를 통하여 함수를 추가하는 add() 함수 : 성공 여부를 return Tip : !! 문법은 다른 Javascript 표현식을 Boolean으로 변환하는 간단한 방법
  • 26. 3.3.2 Self-memoizing 함수 • Memoization은 이전의 결과값을 기억할 수 있게 함수를 만드는 과정 메모이제이션은 이전의 결과값을 기억할 수 있게 함수를 만드는 과정 소수를 구하는 간단한 예제를 살펴보자.
  • 27. 3.3.2 Self-memoizing 함수 // Listing 3.13 : http://jsbin.com/arenaz function isPrime(value) { if (isPrime.answers[value] != null) { //#1 return isPrime.answers[value]; //#1 } //#1 var prime = value != 1; // 1 can never be prime for (var i = 2; i < value; i++) { if (value % i == 0) { prime = false; break; } } return isPrime.answers[value] = prime; //#2 } isPrime.answers = {}; //#3 assert(isPrime(5), "5 is prime!" ); //#4 assert(isPrime.answers[5], "The answer was cached!" ); //#4 [Listing 3.13] #1 이미 캐시 된 값이 있다면 해당 값 return #2 아니라면 계산 된 소수값을 저장
  • 28. 3.3.2 Self-memoizing 함수 // http://jsbin.com/arenaz/2 function isPrime(value) { if (!isPrime.anwers) isPrime.answers = {}; if (isPrime.answers[value] != null) { //#1 return isPrime.answers[value]; //#1 } //#1 var prime = value != 1; // 1 can never be prime for (var i = 2; i < value; i++) { if (value % i == 0) { prime = false; break; } } return isPrime.answers[value] = prime; //#2 } assert(isPrime(5), "5 is prime!" ); //#4 assert(isPrime.answers[5], "The answer was cached!" ); //#4 http://jsbin.com/arenaz/2 이와 같이 answers 속성 정의를 함수 초반에 해도 되겠다.
  • 29. 3.3.2 Self-memoizing 함수 이런 방법의 장점 : • 이전의 계산 된 값을 활용함으로써 향 상 된 퍼포먼스 • 특별한 추가 동작 없이 원할하게 동작 단, 메모리를 희생하기 때문의 주의! 이런 방법의 장점 : 이전의 계산 된 값을 활용함으로써 향상 된 퍼포먼스 특별한 추가 동작 없이 원할하게 동작 단, 메모리를 희생하기 때문의 주의
  • 30. 3.3.2 Self-memoizing 함수 function getElements( name ) { if (!getElements.cache) getElements.cache = {}; return getElements.cache[name] = getElements.cache[name] || document.getElementsByTagName(name); } [또 다른 예제코드] 함수 속성으로 캐시를 하여 코드가 간단해지고, 더 복잡한 쿼리 프로세스를 거치지 않는다.
  • 31. 3.3.2 Self-memoizing 함수 function getElements( name ) { if (!getElements.cache) getElements.cache = {}; return getElements.cache[name] = getElements.cache[name] || document.getElementsByTagName(name); } Average Min Max Deviation non-cached 12.58 12 13 0.50 version cached version 1.73 1 2 0.45 단위 ms, 1000회 반복, Firefox 3 결과 [또 다른 예제코드] 함수 속성으로 캐시를 하여 코드가 간단해지고, 더 복잡한 쿼리 프로세스를 거치지 않는다.
  • 32. 3.3.2 Self-memoizing 함수 함수 속성의 유용성 : • 한 공간에 캐시 정보를 저장/관리 • 즉, 추가 공간이나 캐시 객체가 필요 없다. *함수 속성의 유용성* 한 공간에 캐시 정보를 저장/관리. 즉, 추가 공간이나 캐시 객체가 필요 없다.
  • 33. 3.4 Context • 어마어마한 강점이자 해매이기쉬운 내용 • this : 모든 함수 안에 존재 3.4 Context 어마어마한 강점이자 해매이기쉬운 내용 this : 모든 함수 안에 존재
  • 34. 3.4.1 함수 내부 Context // Listing 3.14 : http://jsbin.com/uzucop var katana = { isSharp: true, //#1 use: function(){ //#2 this.isSharp = !this.isSharp; //#2 } //#2 }; katana.use(); //#3 assert(!katana.isSharp, //#4 "The value of isSharp has been changed!"); 3.4.1 함수 내부 Context [Listing 3.14] katana 객체 이름을 사용하여 직접적인 호출 없이 isSharp 속성에 접근 (만일 katana라는 객체 이름을 sword로 바꾼다면?)
  • 35. 3.4.2 독립적인 함수 내부 Context // Listing 3.15 : http://jsbin.com/ukuwev function katana(){ //#1 this.isSharp = true; //#1 } //#1 katana(); //#2 assert(isSharp === true, //#3 "A global property now exists."); 3.4.2 독립적인 함수 내부 Context 독립적(top-level)으로 사용될 경우는 어떨까? [Listing 3.15] 전역 객체(window)에서 선언 된 경우 this 역시 window context 참조 이런 context 표현은 여러 상황에서 함수를 다룰 때 완전 중요하다.
  • 36. 3.4.2 독립적인 함수 내부 Context // Listing 3.15 : http://jsbin.com/ukuwev function katana(){ //#1 this.isSharp = true; //#1 } //#1 katana(); //#2 assert(isSharp === true, //#3 "A global property now exists."); NOTE ECMAScript 3.1 strict mode 에서는 객체 속성으로 함수 선언이 되지 않은 경우 더 이상 전역 객체 context를 가지지 않는다. 3.4.2 독립적인 함수 내부 Context Note : ECMAScript 3.1 strict mode 에서는 객체 속성으로 함수 선언이 되지 않은 경우 더 이상 전역 객체 context를 가지지 않는다.
  • 37. 3.4.3 Context 정의 • Context는 함수를 어떻게 호출하느냐에 따라 결정할 수 있다. 3.4.3 Context 정의 함수의 context를 고유 기능이라 생각하지만, 현실은 그렇지 않다. 함수를 어떻게 호출하느냐에 따라 결정할 수 있다.
  • 38. 3.4.3 Context 정의 call(), apply() • 모든 함수에 존재 • 함수 호출에 이용 - context 정의 • 전달 인자 구체화 3.4.3 Context 정의 call(), apply() 모든 함수에 있으며, 함수 호출에 이용, context 정의, 전달 인자 구체화
  • 39. 3.4.3 Context 정의 // Listing 3.16 : http://jsbin.com/ibipeg function fn(){ return this; } //#1 var ronin = {}; //#2 assert(fn() == this, "The context is the global object."); //#3 assert(fn.call(ronin) == ronin, //#4 "The context is changed to a specific object." ); [Listing 3.16] call() 함수의 첫번째 인자로 간단하게 context를 정의할 수 있다.
  • 40. 3.4.3 Context 정의 // Listing 3.17 : http://jsbin.com/unesoq function add(a, b){ //#1 return a + b; //#1 } //#1 assert(add.call(this, 1, 2) == 3, //#2 ".call() takes individual arguments" ); assert(add.apply(this, [1, 2]) == 3, //#3 ".apply() takes an array of arguments" ); call : 각각 개별로 인자 전달 apply : 배열형태로 인자 전달 call(), apply() 차이점 : 인자 전달 방법 [Listing 3.17] call() : 각각 개별로 인자 전달 apply() : 배열형태로 인자 전달 이들의 실질적인 사용법을 간단한 예제로 알아보자.
  • 41. 3.4.4 반복문과 콜백 • 직진하듯 진행하는 함수 호출이 필요할 때 직접 호출만으로 힘들다면, 콜백 함수를 이용 • 함수의 참조를 다른 함수로 전달 → 다른 함수에선 이 참조를 이용해 콜백 호출 • 대부분 javascript 라이브러리의 반복문에서 활용 3.4.4 반복문과 콜백 직진하듯 쭉 진행하는 함수 호출이 필요할 때, 직접 호출만으로 힘들다면, 콜백 함수를 이용 함수의 참조를 다른 함수로 전달 -> 다른 함수에선 이 참조를 이용해 콜백 호출 대부분 javascript 라이브러리의 반복문에서 활용
  • 42. 3.4.4 반복문과 콜백 // Listing 3.18 : http://jsbin.com/elilix function loop(array,fn){ //#1 for (var i = 0; i < array.length; i++) //#1 if (fn.call(array, array[i], i) === false) break; //#1 } //#1 var num = 0; //#2 var numbers = [4,5,6]; //#2 loop(numbers, function(value, n){ assert(this === numbers, //#3 "Context is correct."); assert(n == num++, //#4 "Counter is as expected."); assert(value == numbers[n], //#5 "Value is as expected."); }); [Listing 3.18] 기존의 for 반복문에 비해 유연함 콜백은 인스턴스 생성 없이 동작하며, this context로 언제든 원래 배열에 접근 가능
  • 43. 3.4.4 반복문과 콜백 • 라이브러리에선 정말 중요한 요소 • 비동기적,Ajax 응답 반응, 배열에서 검색) (버튼 클릭, 비결정적 행동 라이브러리에선 정말 중요한 요소 비동기적, 비결정적 행동 (버튼 클릭, Ajax 응답 반응, 배열에서 검색)
  • 44. 3.4.5 배열 메서드 속이기 배열과 유사한 객체를 생성했다면, ➡ 배열과 유사하게 동작하지만 실질적으 로 배열의 추가 기능은 가지지 못한다. 3.4.5 배열 메서드 속이기 배열과 유사한 객체를 생성했다면, 배열과 유사하게 동작하지만 실질적으로 배열의 추가 기능은 가지지 못한다. 해결책으로 새 객체를 생성할 때 마다 새로운 배열도 생성하고 따라서 필요한 속성과 메서드를 만든다. 하지만 매우 느림 일반 객체에 우리가 필요한 기능이 적용가능한지 실험해보자.
  • 45. 3.4.5 배열 메서드 속이기 // Listing 3.19 : http://jsbin.com/utibam/2 var elems = { length: 0, //#1 add: function(elem){ //#2 Array.prototype.push.call(this, elem); }, find: function(id){ //#3 this.add(document.getElementById(id)); } }; elems.find("first"); //#4 assert(elems.length == 1 && elems[0].nodeType, //#4 "Verify that we have an element in our stash"); //#4 elems.find("second"); //#4 assert(elems.length == 2 && elems[1].nodeType, //#4 "Verify the other insertion"); //#4 (우선, 코드에서 div#first, div#second DOM노드를 가지고 있다고 가정) add() 함수에서 네이티브 객체 메서드(Array.prototype.push) 사용 보통 이 함수는 배열 context 연산에 사용되지만 여기선 call() 메서드를 사용해 객체 context를 넘겨 마치 배열인양 동작 length 속성도 증가됨! 이런 틀을 무너뜨리는 예시는 유순한 함수 context 위력을 보여준다.
  • 46. 3.5 Variable-length 인자 리스트 3.5 Variable-length 인자 리스트 유연하여 강력한 함수 인자의 특징을 살펴보자.
  • 47. 3.5.1 배열에서 최소/최대 숫자 • 기본적인 기능이 아니라서 직접 정의해 보자. • 단순히 반복문으로 배열을 탐색하는 방 법이 아닌 다른 방법으로. • Math.min(), Math.max() 메서드는 인자 갯수 상관없이 처리 가능 3.5.1 배열에서 최소/최대 숫자 Javascript 언어에서 기본적으로 정의되어 있지 않기 때문에 직접 만들어보자. 반복문으로 배열을 탐색하는 방법이 있지만 다른 방법으로. Math.min(), Math.max() 메서드는 인자 갯수 상관없이 처리 가능
  • 48. 3.5.1 배열에서 최소/최대 숫자 // Listing 3.20 : http://jsbin.com/uxipot function smallest(array){ //#1 return Math.min.apply(Math, array); //#1 } //#1 function largest(array){ //#2 return Math.max.apply(Math, array); //#2 } //#2 assert(smallest([0, 1, 2, 3]) == 0, //#3 "Located the smallest value."); //#3 assert(largest([0, 1, 2, 3]) == 3, //#3 "Located the largest value."); //#3 [Listing 3.20] apply() 호출할 때 context는 Math 객체로 지정. 상관없이 min(), max() 동작은 하지만 깔끔한 context 유지를 위해.
  • 49. 3.5.2 함수 오버로딩 3.5.2 함수 오버로딩 앞의 3.2절에서 보았던 arguments 변수에 대해 자세히 살펴보자.
  • 50. Detecting and Traversing Arguments // Listing 3.21 : http://jsbin.com/ereseg function merge(root){ //#1 for (var i = 1; i < arguments.length; i++) { for (var key in arguments[i]) { root[key] = arguments[i][key]; } } return root; } var merged = merge( //#2 {name: "Batou"}, //#2 {city: "Niihama"}); //#2 assert(merged.name == "Batou", //#3 "The original name is intact."); //#3 assert(merged.city == "Niihama", //#3 "And the city has been copied over."); //#3 * Detecting and Traversing Arguments 하나의 root 객체에 다중 객체를 병합 [Listing 3.21] 가능한 하나의 전달받은 인자(root)는 이름으로 참조할 수 있도록. 추가로 전달 받는 인자는 arguments 변수를 통하여. Tip : 전달된 인자가 있는지 확인하는 방법 : 인자이름 === undefined
  • 51. Slicing and Dicing an Arguments List // Listing 3.22 : http://jsbin.com/iwacod function multiMax(multi){ return multi * Math.max.apply(Math, arguments.slice(1)); } assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)"); * Slicing and Dicing an Arguments List 첫번째 인자와 나머지 인자 중 최대값을 곱하는 함수 [Listing 3.22] 뭔일이여? arguments 변수는 실제 배열이 아니다.
  • 52. Slicing and Dicing an Arguments List // Listing 3.22 : http://jsbin.com/iwacod function multiMax(multi){ return multi * Math.max.apply(Math, arguments.slice(1)); } assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)"); arguments는 실제 배열이 아니다. 뭔일이여? arguments 변수는 실제 배열이 아니다.
  • 53. 3.5.2 함수 오버로딩 // Listing 3.23 : http://jsbin.com/iwacod/2 function multiMax(multi){ return multi * Math.max.apply(Math, Array.prototype.slice.call(arguments, 1)); //#1 } assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)"); [Listing 3.23] 앞서 봤던 배열 prototype 방식으로 해결
  • 54. 3.5.3 함수 오버로딩 • 겉으로 보기엔 같은 이름의 함수이지만 서로 다른 동작을 하는 형태 3.5.3 함수 오버로딩 겉으로 보기엔 같은 이름의 함수이지만 서로 다른 동작을 하는 형태에 대해 보자.
  • 55. The Function's Length Property function makeNinja(name){} function makeSamurai(name, rank){} assert( makeNinja.length == 1, "Only expecting a single argument" ); assert( makeSamurai.length == 2, "Two arguments expected" ); length : 함수 선언에서 명명 된 인자의 갯수 arguments.length : 실제로 전달 받은 인자의 갯수 * The Function's Length Property 잘 알려지지 않았지만 모든 함수엔 length 속성이 있다. http://jsbin.com/ubacul length : 함수 선언에서 명명 된 인자의 갯수 arguments.length : 실제로 전달 받은 인자의 갯수
  • 56. Overloading Functions By Argument Count // Listing 3.24 : http://jsbin.com/ayuher function addMethod(object, name, fn) { var old = object[name]; //#1 object[name] = function(){ if (fn.length == arguments.length) //#2 return fn.apply(this, arguments) //#2 else if (typeof old == 'function') //#3 return old.apply(this, arguments); //#3 }; } * Overloading Functions By Argument Count 몇개의 인자를 전달받느냐에 따라 서로 다르게 동작 if-then-else-if 명세
  • 57. Overloading Functions By Argument Count // Listing 3.24 : http://jsbin.com/ayuher function addMethod(object, name, fn) { var old = object[name]; //#1 object[name] = function(){ if (fn.length == arguments.length) //#2 return fn.apply(this, arguments) //#2 else if (typeof old == 'function') //#3 return old.apply(this, arguments); //#3 }; } addMethod(myObject,'whatever',function(){ /* do something */ }); addMethod(myObject,'whatever',function(p1){ /* do something else */ }); addMethod(myObject,'whatever',function(){ /* do something */ }); myObject.whatever 속성에 익명 함수를 적용 addMethod(myObject,'whatever',function(p1){ /* do something else */ }); 이 때 같은 myObject.whatever()를 호출해도 서로 다른 익명 함수가 호출된다. -- #1 이미 name 속성으로 선언된 내용이 있다면 old 변수에 저장된다. - 클로져 object.name() 함수가 실행 되었을때, #2 최근에 전달 받았던 fn 인자의 갯수와 동일 하다면 바로 fn 익명 함수를 실행 #3 위의 인자 갯수와 다르다고, old에 저장 된 함수가 있다면 해당 함수를 실행 (#3)부분이 매우 어려운듯
  • 58. // Listing 3.25 : http://jsbin.com/ayuher Overloading Functions By Argument Count var ninjas = { values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"] //#1 }; addMethod(ninjas, "find", function(){ //#2 return this.values; }); // Listing 3.24 : http://jsbin.com/ayuher function addMethod(object, name, fn) function(name){ addMethod(ninjas, "find", { //#3 var old = object[name]; =i[];0; i < this.values.length; i++) var ret //#1 for (var = object[name] = function(){ if (this.values[i].indexOf(name) == 0) ret.push(this.values[i]); if (fn.length == arguments.length) //#2 return ret; return fn.apply(this, arguments) }); //#2 else if (typeof old == 'function') //#3 addMethod(ninjas, "find", function(first, last){ //#4 return old.apply(this, arguments); var ret = []; //#3 }; for (var i = 0; i < this.values.length; i++) if (this.values[i] == (first + " " + last)) } ret.push(this.values[i]); return ret; }); addMethod(myObject,'whatever',function(){ /* do something */ }); assert(ninjas.find().length == 3, //#5 "Found all ninjas"); addMethod(myObject,'whatever',function(p1){ /* do something assert(ninjas.find("Sam").length == 1, else */ }); "Found ninja by first name"); assert(ninjas.find("Dean", "Edwards").length == 1, "Found ninja by first and last name"); assert(ninjas.find("Alex", "X", "Russell") == null, "Found nothing"); [Listing 3.25] 각 인자의 갯수마다 다르게 처리되는 모습을 볼 수 있다. (오버로딩처럼 보임) 제약사항 : 오직 인자의 갯수에 따라 판단 오버로딩 된 함수는 호출에 부하가 있다.
  • 59. 3.6 함수 체크 • Firefox 2, 3 : HTML 객체 엘리먼트를 typeof로 확인하면 잘못 된 "function" 결과 • Firefox 2 : 정규식을 함수처럼 호출 가능. /test/("a test") 하 지만 Firefox 2에서는 잘못 된 "function" 결과 • IE : iframe 같이 다른 윈도우 영역에서 타입을 찾으려하면 'unknown' 결과 • Safari : DOM Nodelist가 "function" 타입으로 인식 typeof document.body.childNodes == "function" 3.6 함수 체크 typeof 활용하여 함수 타입을 확인 - Firefox 2, 3 : HTML 객체 엘리먼트를 typeof로 확인하면 잘못 된 "function" 결과 - Firefox 2 : 정규식을 함수처럼 호출 가능. /test/("a test") 하지만 Firefox 2에서는 잘못 된 "function" 결과 - IE : iframe 같이 다른 윈도우 영역에서 타입을 찾으려하면 'unknown' 결과 - Safari : DOM Nodelist가 "function" 타입으로 인식: typeof document.body.childNodes == "function"
  • 60. 3.6 함수 체크 function isFunction(fn) { return Object.prototype.toString.call(fn) === "[object Function]"; } 해결책으로 Object.prototype.toString 활용
  • 61. 3.7 요약 • 함수가 동작하는 다양한 방법을 보았다. • 함수 내부 동작에 이해가 근본적으로 높은 품질의 코드를 생성 • 함수를 정의하는 여러 기술과 각각의 이점 • 익명 함수와 재귀에서 arguments.callee 사용으로 문제 해결 • 함수를 객체와 같이 사용하여 추가적인 데이터 저장의 이점 • 함수에서 context 동작과 apply, call 사용으로 스스로 조작하는 방법 • 여러 형태의 인자에 대해 처리할 수 있는 함수 (그리고 오버로딩) • 마무리로 객체 타입과 함수 타입에 관한 크로스 브라우징 이슈 3.7 Summary Javascript에서 함수가 동작하는 다양한 방법을 보았다. 함수 내부 동작에 이해가 근본적으로 높은 품질의 코드를 생성 함수를 정의하는 여러 기술과 각각의 이점 익명 함수와 재귀에서 arguments.callee 사용으로 문제 해결 함수를 객체와 같이 사용하여 추가적인 데이터 저장의 이점 함수에서 context 동작과 apply, call 사용으로 스스로 조작하는 방법 여러 형태의 인자에 대해 처리할 수 있는 함수 (그리고 오버로딩) 마무리로 객체 타입과 함수 타입에 관한 크로스 브라우징 이슈