본문으로 바로가기

4. 함수와 프로토타입 체이닝 (1)

category language/JavaScript 2019. 11. 21. 01:01

자바스크립트에서 가장 중요한 개념 : 함수

모듈화 처리나 클로저, 객체 생성 등 자바스크립트의 근간이 되는 많은 기능 제공


  • 함수 생성
  • 함수 객체
  • 다양한 함수 형태
  • 함수 호출과 this
  • 프로토타입과 프로토타입 체이닝

4.1 함수 정의

자바스크립트에서 함수를 생성하는 3가지 방법

  • 함수 선언문 function statement
  • 함수 표현식 function expression
  • Function() 생성자 함수

4.1.1 함수 리터럴

자바스크립트에서는 함수도 일반 객체처럼 값으로 취급된다.

객체 리터럴 방식으로 일반 객체를 생성할 수 있는 것처럼, 자바스크립트에서는 함수 리터럴을 이용해 함수를 생성할 수 있다. (함수 선언문이나 함수 표현식 방법에서 사용)


function add(x, y) {
	return x+y;
}

 

  1. function 키워드 : 자바스크립트 함수 리터럴은 function 키워드로 시작.
  2. 함수명 (add) : 함수 몸체의 내부 코드에서 자신을 재귀적으로 호출하거나, 또는 자바스크립트 디버거가 해당 함수를 구분하는 식별자로 사용됨. 함수명은 선택 사항 함수명이 없는 함수를 익명 함수라고 한다.
  3. 매개변수 리스트 (x, y) : 타입을 기술하지 않음
  4. 함수 몸체 : 실제 함수가 호출됐을 때 실행되는 코드 부분

4.1.2 함수 선언문 방식으로 함수 생성하기

함수 리터럴 형태와 같음.

but

반드시 함수명이 정의되어 있어야 한다.

예제 4-1 add() 함수 생성 (함수 선언문 방식)

// add() 함수 선언문
function add(x, y) {
    return x + y;
}

console.log(add(3, 4)) // (출력값) 7

 

4.1.3 함수 표현식 방식으로 함수 생성하기

자바스크립트에서는 함수도 일반 객체처럼 값으로 취급된다.

함수도 숫자나 문자열처럼 변수에 할당하는 것이 가능하다.


함수 표현식 : 함수 리터럴로 하나의 함수를 만들고 여기서 생성된 함수를 변수에 할당하여 함수를 생성하는 것


예제 4-2 add() 함수 생성 (함수 표현식 방식)

// add() 함수 표현식
var add = function (x, y) {
    return x + y;
};

var plus = add;

console.log(add(3, 4)); // (출력값) 7
console.log(plus(5, 6)); // (출력값) 11

 

함수 표현식 방법에서는 함수 이름이 선택 사항이며, 보통 사용하지 않는다.

그 외에는 함수 선언문 문법과 거의 유사


  • add 변수는 함수 리터럴로 생성한 함수를 참조하는 변수. 함수 이름이 아니다. 여기서는 함수 변수라고 부름.
  • 함수 표현식으로 생성된 함수를 호출하려면 함수 변수를 사용
  • add가 가지는 것은 함수의 참조값이므로 또다른 변수 plus에도 할당할 수 있다.

즉, addplus는 같은 익명 함수를 가리킨다.


위의 예제를 요약하자면, 인자로 넘겨진 두 수를 더하는 익명 함수(anonymous function)을 만들고 이를 add 변수에 할당한 것을 다시 plus에 할당한 것.

이런 익명 함수의 호출은 함수 변수에 함수 호출 연산자인 ()를 붙여서 기술하는 것으로 가능.


예제 4-3 기명 함수 표현식의 함수 호출 방법

var add = function sum(x, y) {
    return x + y;
};

console.log(add(3,4));  // (출력값) 7
console.log(sum(3, 4));
        // (출력값) Uncaught ReferenceError: sum is not defined 에러 발생

 

함수 표현식에서 사용된 함수 이름은 외부 코드에서 접근 불가능.


함수 표현식에 사용된 함수 이름은 정의된 함수 내부에서 해당 함수를 재귀적으로 호출하거나, 디버거 등에서 함수를 구분할 때 사용됨.


함수 선언문 형식으로 정의된 add() 함수는 자바스크립트 엔진에 의해 다음과 같은 함수 표현식 형태로 변경된다.


var add = function add(x, y) {
	return x + y;
}

 

함수 이름과 함수 변수의 이름이 add로 같으므로, 함수 이름으로 함수가 호출되는 것처럼 보이지만, 실제로는 add 함수 변수로 함수 외부에서 호출이 가능하게 된 것.


즉, 함수 표현식에서는 함수 이름이 선택 사항이지만, 이러한 함수 이름을 이용하면 함수 코드 내부에서 함수 이름으로 함수의 재귀적인 호출 처리가 가능.


예제 4-4 함수 표현식 방식으로 구현한 팩토리얼 함수

var factorialVar = function factorial(n) {
    if(n <= 1) {
        return 1;
    }
    return n * factorial(n-1);
};

console.log(factorialVar(3));   // (출력값) 6
console.log(factorial(3));  // (출력값) Uncaught ReferenceError: factorial is not defined

 

function statement와 function expression에서의 세미콜론

일반적으로 자바스크립트 코드를 작성할 때 함수 선언문 방식으로 선언된 함수의 경우는 함수 끝에 세미콜론(;)을 붙이지 않지만, 함수 표현식 방식의 경우는 세미콜론(;)을 붙이는 것을 권장한다.

자바스크립트는 C와 같이 세미콜론 사용을 강제하지는 않는다. 자바스크립트 인터프리터가 자동으로 세미콜론을 삽입시켜 주기 때문이다. 그렇다고 해서 세미콜론 사용을 신경쓰지 않는다면, 심각한 디버깅 상황에 직면할 수 있다.

다음 예제의 원래 의도는 단순히 42를 리턴하는 func() 함수를 정의하고, 그런 다음 즉시 실행 함수 형식으로 “function called”를 출력하는 것


var func = function() {
	return 42;
} // 세미콜론을 사용하지 않음
(function() {
	console.log("function called");
})();

 

의도와는 다르게 ‘number is not a function’이라는 에러 발생.

그 이유는 자바스크립트 파서가 func()의 함수 정의에서 세미콜론을 사용하지 않아, return 42; 문장을 지나 func()의 함수 정의 끝에 있는 중괄호(}) 만으로 func() 함수가 끝났다고 판단하지 않기 때문. 그리고 자바스크립트 파서는 이후에 괄호에 둘러싸여 정의된 즉시 실행 함수를 보고 이를 마치 func() 함수 호출 연산으로 생각해서 func() 함수를 호출해 버린다. 그렇기 때문에 func() 함수가 호출되면 42가 반환되고, 즉시 실행 함수를 실행하려고 남겨둔 마지막 () 괄호가 있으므로 42(); 형태로 또다시 함수를 호출하려고 시도한다. 그러나 42는 숫자이지 함수가 아니므로 ‘number is not a function’ 에러가 발생하게 된다.

참고 : 구글의 자바스크립트 스타일 가이드


4.1.4 Function() 생성자 함수를 통한 함수 생성하기

자바스크립트의 함수도 Function()이라는 기본 내장 생성자 함수로부터 생성된 객체이다. 앞에서 설명한 함수 선언문과 함수 표현식 방식도 Function() 생성자 함수가 아닌 함수 리터럴 방식으로 함수를 생성하지만, 내부족으로는 Function() 생성자 함수로 함수가 생성됨.


Function() 생성자 함수로 함수를 생성하는 문법

new Function (arg1, arg2, ... argN, functionBody)
  • arg1, arg2,…argN : 함수의 매개변수
  • functionBody : 함수가 호출될 때 실행될 코드를 포함한 문자열

예제 4-5 Function() 생성자 함수를 이용한 add() 함수 생성

var add = new Function('x', 'y', 'return x+y');
console.log(add(3, 4)); // (출력값) 7

 

하지만 일반적으로 Function() 생성자 함수를 사용한 함수 생성 방법은 자주 사용되지 않는다. 실제 사용하기보다는 다른 사람이 작성한 소스를 분석할 때 나오는 경우가 있음.


4.1.5 함수 호이스팅

함수를 생성하는 3가지 방법들 사이에는 동작 방식이 약간 차이가 있다. 그 중 하나가 함수 호이스팅(Function Hoisting)


자바스크립트 Guru로 알려진 더글러스 크락포드는 함수 표현식만을 사용할 것을 권함. (<더글라스 크락포드의 자바스크립트 핵심 가이드> (2008, 한빛미디어)) 그 이유 중 하나가 함수 호이스팅.


예제 4-6 함수 선언문 방식과 함수 호이스팅

console.log(add(2,3));   // 5

// 함수 선언문 형태로 add() 함수 정의
function add(x, y) {
    return x + y;
}

console.log(add(3, 4));  // 7

 

1번째 줄의 시점에서는 add() 함수가 정의되지 않았음에도 밑에서 정의된 add() 함수를 호출하는 것이 가능. 함수가 자신이 위치한 코드에 상관없이 함수 선언문 형태로 정의한 함수의 유효 범위는 코드의 맨 처음부터 시작한다 함수 호이스팅


즉, 함수 호이스팅은 함수를 사용하기 전에 반드시 선언해야 한다는 규칙을 무시하므로 코드의 구조를 엉성하게 만들 수도 있다고 지적하며, 함수 표현식 사용을 권장.


예제 4-7 함수 표현식 방식과 함수 호이스팅

add(2,3);   // uncaught type errer

// 함수 표현식 형태로 add() 함수 정의
var add = function (x, y) {
    return x + y;
};

add(3, 4);  // 7

 

add() 함수는 함수 표현식 형태로 정의되어 있어 호이스팅이 일어나지 않는다. 1번째 줄에서는 아직 add() 함수가 생성되기 전이므로 uncaught type error 발생


함수 호이스팅이 발생하는 원인은 자바스크립트의 변수 생성(Instantiation)과 초기화(Initialization)의 작업이 분리되어 진행되기 때문 (5장에서 더 자세히 다룸)


#책/인사이드자바스크립트