[JS] (12) 함수 - 1 | 모던 자바스크립트 Deep Dive

함수

함수란 '입력'과 '출력'의 일련의 과정을 문(statement)로 구현하고 코드블록을 감싸서 하나의 실행단위로 정의한 것이다.

function add (x,y) {
	return x+y;
    } //함수리터럴 => 함수이름 + 매개변수 목록() + 함수 몸체{}
// 매개변수 = x, y
// 함수 이름 = add
// 반환값 = x+y

add(1,2); // 7
//인수 = 2,5

함수의 사용 이유

  1. 코드의 가독성
  2. 재사용성 -> 신뢰성
  3. 유지보수의 편의성

자바스크립트에서의 함수

자바스크립트에서 함수는 객체 타입의 값이다.

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

객체 타입이기 때문에 변수에 함수를 할당할 수 있다.
함수 리터럴(표기법) 또한 표현식으로 값을 생성하며, 하나의 객체로 취급된다.
'함수 이름이 있으면 기명함수, 함수 이름이 없으면 익명함수'

  • 하지만!
    일반 객체 타입과는 다른데,
    일반 객체는 호출이 불가이지만 함수에 경우 호출이 가능하다.
    또한, 일반 객체에는 없는 함수 객체만의 고유한 프로퍼티를 갖는다.
    함수가 객체인 것은 자바스크립트만의 중요한 특징인데, 이에 대해서는 나중에 다루도록 하겠다.

함수 정의

함수를 정의하는 방법에는 4가지가 있다.

1. 함수 선언문

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

함수 선언문은 리터럴과 형태가 동일하나, 함수 선언문에서는 함수 이름을 생략할 수 없음!
함수 선언문은 표현식이 아니기 때문에 원래는 값을 할당 할 수는 없다. 하지만, 작동은 한다.

var add = function add(x,y){
	return x+y; 
}
console.log(add(2,5)); // 7

이러한 이유는 자바스크립트가 선언문인지 표현식(리터럴)인지 이 두개를 동일하게 해석하는 경우가 있기 때문이다.

{}는 블록문으로 해석 할 수도 객체리터럴로 해석 할 수도 있다. 이는 문맥에 따라 달라지는데, 단독으로 사용된 {}는 블록문으로, {}가 값으로 평가될때 (할당연산자의 우변)일 때는 객체로 해석한다.

아래 코드를 보자.

//기명 함수 리터럴을 단독으로 사용되면 함수 선언문으로 해석됨
function foo() {console.log('foo');}
foo(); //'foo' -> 함수의 호출이 가능

//함수 리터럴을 ()안에 넣으면 피연산자로 인식 -> 함수 리터럴 표현식으로 해석됨
(function bar() {console.log('bar');})
bar(); //ReferenceError: bar is not definded -> 함수의 호출이 불가

이러한 차이가 왜 생기느냐?
함수 리터럴 개념 중, "함수 이름은 함수 몸체 내에서만 참조가 가능하다."
따라서 이 원칙에 따르면 원래는 선언문과 리터럴 둘다 호출이 불가능 해야한다.

허나,
함수 선언문에서는 자바스크립트가 암묵적으로 함수이름과 동일한 식별자를 생성하며, 그 생성자에 함수 객체를 할당하기 때문에 선언문에 경우 호출이 가능하다.
함수는 함수 이름으로 호출되는 것이 아니고 (같은 이름의) 함수 객체를 가르키는 '식별자'를 통해 호출된다.
이러한 자바스크립트의 암묵적 수행으로 인해 함수 선언문의 동작은 함수를 변수에 저장하는 표현식처럼 전환되어 객체를 생성한다. (근데 또 완전 동일한 동작은 아님....😤)


2. 함수 표현식

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

함수 표현식은 마치 객체타입의 값처럼 변수에 할당할 수 있으며, 프로퍼티 동작도 가능하고, 배열의 요소 또한 가능하다.
이러한 함수의 성질을 '일급 객체'라 한다.

우변에 해당하는 함수 리터럴의 함수이름은 생략이 가능하다. -익명함수-
결국. 함수 이름은 별로 중요한 것이 아니다. 그 함수를 불러올 때는 식별자(변수명)으로 호출하기 때문에!

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

add(1,2) //3
foo(1,2) //Error

함수 선언문과 함수 표현식의 생성시점 차이

선언문과 표현식의 동작은 식별자에 함수를 할당하고 객체를 저장하는 것은 동일하나
각각 객체(함수)를 생성하는 시점에 차이가 있다.

  • 함수 선언문의 경우 : 런타임 이전에 객체를 생성 = 함수 호이스팅 발생
  • 함수 표현식의 경우 : 할당문이 실행되는 시점에 평가되어 객체를 생성 = 변수 호이이스팅 발생

함수 호이스팅은 런타임 이전에 선언을 위로 끌어올려 식별자에 함수객체를 할당하는 것까지 완료한다.
허나, 변수 호이스팅은 식별자를 생성하기까지만 미리 동작하며 할당은 수행하지 않는다.
(원시타입 변수 선언의 경우도 마찬가지로 변수 호이스팅 ex. var foo = 1;)

따라서, 함수 표현식으로 정의한 함수는 표현식 이후에만 참조 또는 호출을 해야한다.(사용한다)
함수 호이스팅은 "호출하기전 선언을 해야한다."라는 규칙을 깨기 때문에 JavaScript 권위자들은 권장하지 않는다.


3. Function 생성자 함수

var add = new Function('x','y','return x+y');

위 코드와 같이 new 키워드를 사용하여 생성된 함수는 클로저를 생성하지 않는 등 일반 함수와 다르게 동작한다.
일반적으론 잘 사용하지 않음!

4. 화살표 함수(ES6)

var add = (x,y) => x+y;

항상 함수 이름이 없는 익명함수이다!
표기만 간단할 뿐 아니라 내부동작도 간단하며 일반함수와 다른 부분이 있다. (this, 바인딩 등)

정리

이번 포스팅에서는 함수의 선언과 할당을 더불어 함수 생성에 대해 정리하였다.
가장 중요한 것은, 함수의 이름은 함수 내부에서만 호출 할 수 있다는 것.
자바스크립트는 함수를 선언할 때 암묵적 동작을 통해 함수이름과 같은 식별자를 생성하여 함수객체가 저장된 참조를 가르키게 한다는 것!!

그리고, 표현식을 이용하여 함수를 생성하는 것을 권장한다라는 것.

좋은 웹페이지 즐겨찾기