프로그래밍/자바스크립트

Javascript - 함수의 이해

가카리 2015. 1. 22. 22:16
반응형

1.   함수

기본적으로 다음과 같은 4가지의 역할을 가지고 있다.


function 생성자는 잘쓰이지 않음



04-01.html

<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-01</title>

  </head>

  <body>

    <script type="text/javascript">

          // 함수의 정의와 호출

      

      // function 문에 의해 정의된 print 함수는 매개변수 message 전달된 값을 출력합니다.

      function print(message) {

        document.writeln(message);

      }

      

      // function 문에 의해 정의된 println 함수는 매개변수 message 전달된 값과

      // 문자열 '<br/>' 접합연산한 결과를 출력합니다.

      function println(message) {

        document.writeln(message + '<br/>');

      }

      

      // function 문에 의해 정의된 distance 함수는 x, y 프로퍼티를 가진 객체를 매개변수로 하여

      // 내장객체 Math 제공하는 sqrt함수를 호출해 점간의 거리를 반환합니다.

      function distance(p1, p2) {

        var dX = p2.x - p1.x;

        var dY = p2.y - p1.y;

        return Math.sqrt(dX * dX, dY * dY); // 내장객체 Math 제공하는 sqrt함수를 호출합니다.

      }

      

      var pointA = { x : 25, y : 40 };

      var pointB = { x : 50, y : 80 };

      

      print('pointA pointB 사이의 거리: ');

      println(distance(pointA, pointB));

      

      // 함수리터럴에 의해 정의된 area 함수는 x, y 프로퍼티를 가진 객체를 매개변수로 하여

      // 점을 이용해 구성된 사각형의 면적을 반환합니다.

      var square = function(leftTop, rightButtom) {

        var width = rightButtom.x - leftTop.x;

        var height = rightButtom.y - leftTop.y;

        return width * height;

      };

      

      print('pointA pointB 구성한 사각형의 넓이: ');

      println(square(pointA, pointB));

      

      // Function 생성자에 의해 정의된 triangle 함수는 base height 매개변수에 전달된 값을 이용해

      // 삼각형의 면적을 반환합니다.

      var triangle = new Function('base', 'height', 'return (base * height) / 2;');

      print('base height 구성한 삼각형의 넓이: ');

      println(triangle(30, 20));

    </script>

  </body>

</html>


출력화면


2.   변수의 전역스코프와 지역스코프


04-02.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-02</title>

  </head>

  <body>

    <script type="text/javascript">

      // 전역 스코프와 지역 스코프

      

      // 전역 스코프를 가진 전역 변수

      var x = 'global x';  

      var y = 'global y';


      

      function func() {

        

        // 지역 스코프를 가진 지역 변수는 반드시 var 키워드와 함께 선언되어야 합니다.

        var x = 'local x';

        

        // var 키워드 없을 경우 전역스코프에 접근해 동일 이름을 가진 전역변수를 사용하며,

        // 만일 동일 이름의 전역 변수가 없을 경우 전역변수를 새로 등록합니다.

        y = '???';

        

        document.writeln('x: ' + x + '<br/>');

        document.writeln('y: ' + y + '<br/>');

        document.writeln('<br/>');

      }

      

      document.writeln('func() 호출 <br/>');

      document.writeln('x: ' + x + '<br/>');

      document.writeln('y: ' + y + '<br/>');

      document.writeln('<br/>');

      

      document.writeln('func() 호출<br/>');

      func();

      

      document.writeln('func() 호출 <br/>');

      document.writeln('x: ' + x + '<br/>');

      document.writeln('y: ' + y + '<br/>');  

      document.writeln('<br/>');

    </script>

  </body>

</html>




출력화면




3.   함수의 매개변수와 스코프



04-03.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-03</title>

  </head>

  <body>

    <script type="text/javascript">

      // 함수의 매개변수와 스코프

      

      // 값을 매개변수로 전달하는 경우 함수 내에서의 매개변수 조작은 원본 값에 아무런 영향을 미치지 않습니다.

      function swapByValue (x, y) {

        var temp = x;

        x = y;

        y = temp;     

      }

      

      // 참조값을 매개변수로 전달하는 경우 매개변수가 원본 객체를 참조하므로

      // 함수 내에서 매개변수를 통한 객체 조작은 원본 객체에 영향을 미칩니다.

      function swapByReference (o) {

        var temp = o.x;

        o.x = o.y;

        o.y = temp;   

      }

      

      var a = 5;

      var b = 8;

      var obj = { x : 5, y : 8};

      

      document.writeln('swap 함수 호출 <br/>');

      document.writeln('a: ' + a + ', b: ' + b + '<br/>');

      document.writeln('obj.x: ' + obj.x + ', obj.y: ' + obj.y + '<br/>');

      document.writeln('<br/>');

      

      swapByValue(a, b);

      swapByReference(obj);

      

      document.writeln('swap 함수 호출 <br/>');

      document.writeln('a: ' + a + ', b: ' + b + '<br/>');

      document.writeln('obj.x: ' + obj.x + ', obj.y: ' + obj.y + '<br/>');

      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면


4.   함수의 매개변수와 인자




04-04html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-04</title>

  </head>

  <body>

    <script type="text/javascript">

      // 함수의 생략 가능한 매개변수

      

      function sum(array, start, end) {

        // 매개변수 array 전달된 값이 없을 경우 배열을 할당합니다.

        // if 문을 대신해 다음의 || 연산자를 이용한 조건문을 작성할 수도 있습니다.

        // array = array || [];

        if (!array)

          array = [];

        // 매개변수 start 전달된 값이 없을 경우 0 할당합니다

        if (!start) start = 0;

        // 매개변수 end 전달된 값이 없을 경우 배열의 원소의 갯수를 할당합니다.

        if (!end) end = array.length;

            

        // 매개변수 array 전달된 값이  배열 객체일 경우에만 합계를 계산합니다

        if (array instanceof Array) {

          // 매개변수 start end 전달된 값이 숫자일 경우에만 합계를 계산합니다.

          if ((typeof start) != 'number' || (typeof end) != 'number')

            throw new Error('sum(): 두번째 매개변수와 세번째 매개변수의 전달 인자는 숫자여야 합니다.');

       

          var result = 0;

          for (var i = start; i < end; i++) {

            // 배열 array 원소가 숫자 타입일 경우에만 합계를 계산합니다.

            if ((typeof array[i]) != 'number')

              throw new Error('sum(): array[' + i + '] 저장된   ' + array[i] + ' 숫자 타입이 아닙니다.');

            result += array[i];

          }

        

          return result;

          

        } else // 매개변수 array 전달된 값이  배열 객체가 아닐 경우 예외를 발생시킵니다.

          throw new Error('sum(): 첫번째 매개변수의 전달 인자는 배열이어야 합니다.');

        }

      }

      

      var arr1 = [1,2,3,4,5];

      var obj = { name : '홍길동', phone : '010-1234-5678' };

      var arr2 = [1,2,'3rd',4,5];

      

      try {

        document.writeln('sum(arr1, 0, arr1.length): ' + sum(arr1, 0, arr1.length) + '<br/>');

        document.writeln('sum(arr1, 0, 4): ' + sum(arr1, 0, 4) + '<br/>');

        document.writeln('sum(arr1, 0): ' + sum(arr1, 0) + '<br/>');

        document.writeln('sum(arr1, 2): ' + sum(arr1, 2) + '<br/>');

        document.writeln('sum(arr1): ' + sum(arr1) + '<br/>');

        document.writeln('sum(): ' + sum() + '<br/>');

        document.writeln('sum(obj): ' + sum(obj) + '<br/>');

      } catch (e) {

        document.writeln(e + '<br/>');

      }

      

      try {

        document.writeln('sum(arr1, \'x\', 4): ' + sum(arr1, 'x', 4) + '<br/>');

      } catch (e) {

        document.writeln(e + '<br/>');         

      }

      

      try {

        document.writeln('sum(arr2): ' + sum(arr2) + '<br/>');

      } catch (e) {

        document.writeln(e + '<br/>');         

      }

      

      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면



5.   함수와 명시적인 이름을 가진 인자 전달


04-05.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-05</title>

  </head>

  <body>

    <script type="text/javascript">

      // 함수와 명시적인 이름을 가진 인자 전달

    

      function power(arg) {

        // 매개변수 arg 전달된 객체에 base프로퍼티가 정의되어 있지 않을

        // base프로퍼티를 추가하며 1 설정합니다.

        if (!arg.base) {

          arg.base = 1;

        }

        

        // 매개변수 arg 전달된 객체에 exponent프로퍼티가 정의되어 있지 않을

        // exponent프로퍼티를 추가하며 0으로 설정합니다.

        if (!arg.exponent) {

          arg.exponent = 0;

        }

        

        // 내장객체 Math pow 함수를 호출해 결과를 반환합니다.

        return Math.pow(arg.base, arg.exponent);

      }

      

      document.writeln('power({base:3, exponent:2}) 결과 : ' + power({base:3, exponent:2}) + '<br/>');

      document.writeln('power({base:3}) 결과 : ' + power({base:3}) + '<br/>');

      document.writeln('power({exponent:2}) 결과 : ' + power({exponent:2}) + '<br/>');

      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면


6.   함수에 인자로 함수를 전달


04-06.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-06</title>

  </head>

  <body>

    <script type="text/javascript">


      // 사칙연산 관련 메소드를 가진 calculator객체를 정의합니다.

      var calculator = {

        add : function(x, y) {

          return x + y;

        },

      

        subtract : function(x, y) {

          return x - y;

        },

        

        multiply : function(x, y) {

          return x * y;

        },

        

        divide : function(x, y) {

          return x / y;

        }

      };


      

      // 위에 정의된 calculator 객체의  메소드를 첫번째 매개변수의 전달 값으로,

      // 나머지 개의 매개변수는 첫번째 매개변수로 전달된 calculator 객체의 메소드의

      // 매개변수로 사용할 operate1 함수를 정의합니다.

      function operate1(operator, operand1, operand2) {

        return operator(operand1, operand2);

      }

      

      // 첫번째 매개변수로 calculator 객체의 프로퍼티명을 전달하고, 나머지 개의 매개변수는

      // calculator 객체의 메소드의 매개변수로 사용할 operate2 함수를 정의합니다.

      function operate2(operatorName, operand1, operand2) {

        // 프로퍼티 타입이 함수일 경우 메소드를 실행합니다.

        if ((typeof calculator[operatorName]) == 'function')

          return calculator[operatorName](operand1, operand2);

        else

          throw new Error('operator2(): ' + operatorName + '() 정의되어 있지 않은 연산자입니다.');  

      }

      

      // ((3 - 8) + (2 * 5))

      var result1 = operate1(calculator.add, operate1(calculator.subtract, 3, 8),

                                             operate1(calculator.multiply, 2, 5));

      

      document.writeln('result1: ' + result1 + '<br/>');

                                            

      try {

        var result2 = operate2('add', operate2('subtract', 3, 8), operate2('multiply', 2, 5));

        document.writeln('result2: ' + result2 + '<br/>');

      } catch (e) {

        document.writeln(e + '<br/>')

      }


      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면



7.함수에 함수 리터럴을 전달하는 익명함수



04-07.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-07</title>

  </head>

  <body>

    <script type="text/javascript">

      // 함수에 함수 리터럴을 전달하는 익명함수

      

      var calculator = {

        // operate 메소드의 첫번째 매개변수는 함수를 인자로 전달 받습니다.

        operate : function(method, operand1, operand2) {

          if (typeof method == 'function') {

            if (typeof operand1 != 'number' || typeof operand2 != 'number')

              throw new Error('operate(): 두번째, 세번째 매개변수는 반드시 숫자를 전달해야 합니다.');

            return method(operand1, operand2);

          } else

            throw new Error('operate(): 첫번째 매개변수로 함수를 전달해야 합니다.')

        }

      };

      

      try {

        // calculator.operate 메소드의 첫번째 매개변수로 익명함수를 전달합니다.

        var result1 = calculator.operate(function(x, y){ return x + y; }, 2, 3);

        document.writeln('result1: ' + result1 + '<br/>');

        

        // 두번째, 세번째 매개변수로 숫자가 아닌 값을 전달하면 예외를 발생시킵니다.

        var result2 = calculator.operate(function(x, y){ return x + y; }, '2', 3);

        document.writeln('result2: ' + result2 + '<br/>');


      } catch (e) {

        document.writeln(e + '<br/>');

      }

      document.writeln('<br/>');

      

      // 익명함수를 정의하고 바로 호출해 결과를 얻을 수도 있습니다.

      var result3 = (function(x, y){ return x + y;})(2, 3);

      document.writeln('result3: ' + result3 + '<br/>');

      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면



8.중첩 함수


04-08.html



<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-08</title>

  </head>

  <body>

    <script type="text/javascript">

      // 중첩함수

      

      function circle(radius) {

        var pi = 3.14;

        

        // 중첩함수는 내부 변수에 접근가능합니다.

        function area(r) {

          return r * r * pi;

        }

        

        // 중첩함수는 내부에서만 호출 가능합니다.

        return area(radius);

      }

      

      document.writeln('circle(5): ' + circle(5) + '<br/>');

      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면





9. 스코프 체인



04-09.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-09</title>

  </head>

  <body>

    <script type="text/javascript">

      // 스코프 체인

      

      // 1. 전역 레벨의 파싱 결과 전역객체에 프로퍼티 x outer 정의됩니다.

       

      var x = '전역 객체에 등록되어 있는 x 프로퍼티 ';

      

      function outer() {

        var y = 'outer 함수의 호출 객체에 등록되어 있는 y 프로퍼티 ';

        

        function inner() {

          var z = 'inner 함수의 호출 객체에 등록되어 있는 z 프로퍼티 ';

          document.writeln('x: ' + x + '<br/>');

          document.writeln('y: ' + y + '<br/>');

          document.writeln('z: ' + z + '<br/>');

        }

        

        // 3. 함수 레벨의 파싱 결과 inner 함수에 대한 호출 객체에 arguments 프로퍼티가 초기화되고,

        //    프로퍼티 z 정의되고,

        //    outer 함수의 호출 객체와 inner 함수의 호출 객체 간에 스코프 체인이 연결되고,

        //    inner 함수의 코드를 실행합니다.

        //    x 전역객체에, y outer 함수의 호출객체에, z inner 함수의 호출객체에 접근해서

        //    값을 취합니다.

        inner();       

         

      }

      

      // 2. 함수 레벨의 파싱 결과 outer 함수에 대한 호출 객체에 arguments 프로퍼티가 초기화되고,

      //    프로퍼티 y  inner 정의되고,

      //    전역객체와 outer 함수의 호출 객체 간에 스코프 체인이 연결된 ,

      //    outer 함수의 코드를 실행합니다.

      outer();

      

      document.writeln('<br/>');

    </script>

  </body>

</html>



출력화면



10. 콜백 함수



04-10.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-10</title>

  </head>

  <body>

    <script type="text/javascript">

      // 콜백함수

      

      function main() {

        

        var array = [];

        

        // 내장객체 Math random 함수는 0 ~ 1 사이의 값을 반환하고,

        // 내장객체 Math ceil 함수는 인자 이상의 최소 정수를 반환합니다.

        for (var i = 0; i < 10; i++) {

          array[i] = Math.ceil(Math.random() * 45)

        }

        

        // work 함수를 호출하면서 첫번째 매개변수로 처리할 데이터 data,

        // 두번째, 세번째 매개변수로 콜백함수 even odd 전달합니다.

        work(array, even, odd);

        

      }

      

      // 콜백함수 even 짝수가 발견될 때마다 호출될 함수로 당시의 배열 인덱스와 원소를 출력합니다.

      function even(idx, num) {

        document.writeln((idx + 1) + '번째 데이터는 짝수 ' + num + '입니다.<br/>');

      }

      

      // 콜백함수 odd 홀수가 발견될 때마다 호출될 함수로 당시의 배열 인덱스와 원소를 출력합니다.

      function odd(idx, num) {

        document.writeln((idx + 1) + '번째 데이터는 홀수 ' + num + '입니다.<br/>');

      }

      

      // work 함수는 매개변수로 전달받은 배열 data에서

      // 짝수가 발견될 때마다 매개변수로 전달받은 콜백함수 callback1 호출하고,

      // 홀수가 발견될 때마다 매개변수로 전달받은 콜백함수 callback2 호출합니다.

      function work(data, callback1, callback2) {

        for (var i = 0; i < data.length; i++) {

          if (data[i] % 2 == 0)

            callback1(i, data[i]);

          else

            callback2(i, data[i]);

        }

      }

      

      // main 함수를 실행합니다.

      main();


    </script>

  </body>

</html>



출력화면

11. 비공개 속성/함수를 만들 수 있는 함수 클로저 (가장 중요!!)




04-11.html


<!DOCTYPE html>

<html lang="ko">

  <head>

    <meta charset="utf-8" />

    <title>04-11</title>

  </head>

  <body>

    <script type="text/javascript">

      // 클로저

      

      // 1. 전역 레벨의 파싱 결과 전역객체에 프로퍼티 makeId id 정의됩니다.

      

      function makeId() {

        var lastId = 0;

        

        return function() { return ++lastId; };

      }

      

      // 2. 함수레벨의 파싱 결과 makeId() 함수에 대한 호출 객체에 arguments 프로퍼티가 초기화 되고,

      // 프로퍼티 lastId 정의되고

      // 전역객체와 makeId() 함수의 호출객체 간에 스코프 체인이 연결된 ,

      // makeId() 함수가 실행되고, id 익명함수를 반환받습니다.

      var id = makeId();

      

      // 3. 함수 레벨의 파싱 결과 id 함수에 대한 호출 객체에 arguments 프로퍼티가 초기화되고,

      //    makeId 함수의 호출 객체와 id 함수의 호출 객체 간에 스코프 체인이 연결되고,

      //    id 함수의 코드를 실행합니다.

      //    lastId makeId 함수의 호출객체에 접근해서

      //    값을 취합니다.

      document.writeln('id: ' + id() + '<br/>');

      document.writeln('id: ' + id() + '<br/>');

      document.writeln('id: ' + id() + '<br/>');

      document.writeln('id: ' + id() + '<br/>');

      document.writeln('id: ' + id() + '<br/>');

      document.writeln('<br/>');

    </script>

  </body>

</html>





출력 화면





반응형