본문 바로가기
JavaScript Study

JavaScript - #14. 함수(1)

by KMS_99 2023. 8. 29.

함수란 자바스크립트에서 가장 중요한 핵심이다.

 

프로그래밍에서 함수란 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행단위로 정의한 것이다.

 

자바스크립트에서는 왜 함수를 사용할까?

함수는 개발자가 필요로 할 때 실행될 수 있다. 즉 실행 시점을 개발자가 결정할 수 있으며, 여러번 사용이 가능하다.

반복적인 작업이 많을 경우 함수로 정의해서 실행시키는 것이 더욱 효율적이다. 또한 반복이 많은 코드에는 문제가 생길 시 반복되는 코드를 다 수정해야하는 반면 함수는 함수 정의부만 수정하면 되기때문에 유지보수 편의성이 높고, 반복하지 않으니 문제가 생길 가능성도 낮다. 또한 함수에는 식별자가 있기 때문에 함수의 역할을 가독성 좋게 알수 있다.

결론적을 함수를 사용하는 이유는 다음과 같다

 

1. 코드의 재사용성

2. 유지보수 편의성

3. 코드의 신뢰성

4. 코드의 가독성

 

함수는 정의를 통해서 생성이된다. 정의하는 방법에는 여러가지가 있으며, 다음 예시는 그중에서 함수 선언문을 활용한 예시이다.

function add(a,b){
    return a+b;
}

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

위 코드의 구조를 확인해보자.

함수의 구조

함수는 선언부와 호출부로 나누어진다.

선언부에서는 함수를 선언하고 정의하며,

호출부에서는 함수를 실행시키는 문이 위치한다.

 

먼저 함수 선언부에 있는 요소들을 확인하자

- 함수 이름 : 함수 내부에서만 유효한 식별자이며, 이 이름은 함수 외부에서는 사용되지 않는다. 다만 함수 선언문으로 함수를 정의 하였을 때 이 이름이 자동으로 식별자로 변환되기도 한다. 식별자의 역할을 하기때문에 네이밍 규칙을 따라야한다.

- 매개 변수 : 함수 내부에서 변수처럼 사용되며, 때문에 네이밍 규칙을 준수해야한다. 개수의 제한은 없다.

- 반환 값 : 함수의 최종적인 값이며 자바스크립트에서 사용되는 값이면 어떤 타입이든 반환 값이 될 수 있다. return이라는 키워드와 함께쓰이며, 함수에는 반환 값이 꼭 있을 필요는 없다.

 

다음으로 함수 호출부이다.

- 인수 : 인수는 함수를 실행시키는데 필요한 값들이며, 인수를 나열한 순서에 맞게 함수선언부에서 정의한 매개변수로 사용된다. 인수는 매개변수의 수보다 적거나 많아도 오류가 나지 않으며, 적을경우에는 나열된 순서에 맞게 할당이 되며 할당이 되지 못하는 부분에는 undefined가 할당된다. 인수가 매개변수의 수 보다 많을 경우에는 순서대로 매개변수에 할당이 되며, 초과한 인수는 버려진다. 하지만 함수의 arguments 프로퍼티에서는 초과하여 버려진 값도 저장된다.

 

간단하게 함수의 사용이유와 구성을 알아보았으니 위에서 언급했던 여러가지 정의 방법에 대해서 알아보겠다.

 

1. 함수 리터럴

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

console.log(f(1,2)); //3

함수는 객체이다. 객체도 리터럴을 생성 할 수 있듯이, 함수 역시 리터럴로 생성할 수 있다.

함수 리터럴의 구성요소는 다음과 같다. 

1. 함수이름 (생략가능)

2. 매개변수

3. 함수몸체 (코드블록)

 

함수 리터럴은 위 코드에서 보는 것과 같이 변수에 할당될 수 있다. 함수 리터럴은 값으로 사용될 수 있으며, 함수리터럴에서 평가 된 값은 객체이다. 따라서 함수는 객체라고 할 수 있다.

 

함수는 일반객체와 다른 부분이있다.

함수 자체의 고유한 프로퍼티를 가지며, 호출할 수 있는 객체이다.

더 자세한 특징은 추후 일급객체를 배울 때 알아보자.

 

2. 함수 선언문과 함수 표현식

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

console.log(sum(2,5)); //7

함수 선언문은 함수 리터럴의 형태와 같다.

함수 리터럴과 선언문의 차이는 함수이름 생략가능 여부이다.

함수 선언문은 함수 이름을 생략할 수 없다.

 

함수 선언문은 값으로 평가받는 표현식이 아니라 문이다.

따라서 함수 선언문은 변수에 할당 할 수 없다.

하지만 자바스크립트 엔진에서는 함수 선언문을 변수에 할당할 수 있는 것처럼 구동한다.

 

다음 예시를 보자

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

console.log(add(1,2)): // 3

이 코드에서는 let add라는 변수에 함수 선언문이 할당이 되었다.

어떻게 이런일이 가능할까?

바로 자바스크립트 엔진에서 문맥에 따라 함수 리터럴과 함수 선언문으로 해석하기 떄문이다.

함수 리터럴은 함수의 이름을 생략할 수 도 있고 생략을 안할 수도 있다. 따라서 위 코드의 function add(){} 부분은 함수 리터럴이 될 수도 있는 것이다.

그렇다면 자바스크립트 엔진에서 해당부분을 해석하는 기준이 무엇일까?

바로 표현식으로 사용되는지 유무이다.

위 코드에서는 함수 정의부를 let add라는 변수에 할당하려 하고 있다.

코드 문맥상 함수의 정의는 값으로 평가 받는 표현식이여야 하며, 따라서 표현식인 리터럴로 취급 받는 것이다.

 

function foo (){console.log('foo')};
console.log(foo()); // foo

(function bar(){console.log('bar');});
console.log(bar()); //ReferenceError

이 코드에서는 foo는 연산자 없이 단독으로 사용되었기에 함수 선언문으로 활용된다.

함수 선언문을 자바스크립트엔진에서 해석할 때 함수이름과 동일한 함수 식별자를 생성하고 할당하기 때문에 console.log(foo());에서 foo는 함수 이름이 아닌 자동으로 암묵적 생성된 식별자이다. 따라서 오류가 발생하지 않는다.

 

그리고 bar함수는 그룹 연산자 내에 정의되었기 때문에 표현식으로 해석되어야 하며, 리터럴 형식으로 취급받는다.

따라서 console.log(bar());에서는 bar라는 식별자가 없기때문에 참조 오류를 발생시킨다.

 

사실상 함수 선언문 foo는 다음과 같이 해석된다고 보면된다.

let foo = function foo(){
	console.log('foo');
}

여기서 함수 리터럴의 참조값을 가지고 있는 주체는 function foo(){}에서 foo가 아니라 let foo에서의 foo이다.

앞으로 배울 함수 표현식과 거의 동일한 형태이며 완전히 같은 방식으로 작동하지 않는다는 것만 알아두자.

 

이어서 함수 표현식에 대하여 알아보자.

앞에서도 이야기 했지만 함수는 일급 객체이기 때문에 표현식으로 사용될 수 있다.

즉 함수 리터럴로 생성한 함수 객체를 변수에 할당이 가능하다.

함수의 표현식은 다음과 같이 사용된다.

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

console.log(add(5,6));//11

함수 리터럴에서는 함수 이름을 생략할 수 있어 사용하지 않는다.

외부에서 함수를 호출 할 때 함수 이름을 사용할 수 없기 때문에 식별자가 필요한데, 함수 표현식은 정의와 동시에 변수에 할당할 수 있다.

 

여기서 함수 선언문과 표현식의 차이를 하나 더 찾을 수 있다.

자바스크립트의 특징은 호이스팅이 일어난다는 것으로 모든 선언문은 런타임 이전에 선언이 된다.

 

따라서 함수 선언문도 호이스팅이 일어나며, 변수 호이스팅과는 다르게 undefined로 초기화가 되는 것이 아니라 함수 정의 차체를 런타임 이전에 하기 때문에 다음과 같은 코드도 실행이 가능하다.

hoisting();

function hoisting(){
    console.log('hoisting');
}

결과:

hoisting

하지만 함수 선언문과 다르게 함수 표현식은 변수에 함수리터럴을 할당한다.

따라서 함수 표현식에서 일어나는 호이스팅은 변수 호이스팅이다.

 

이 두가지 차이를 알고 있어야한다.

함수 선언문은 정의 후 실행이 되어야 하는 기본적인 규칙을 무시하기 때문에 함수 표현식의 사용을 권장한다.

 

3. Function 생성자 함수

자바스크립트가 기본적으로 제공하는 기본 빌트인 함수 중 Function 생성자 함수를 사용하면 함수 객체를 생성할 수 있다.

new 연산자와 사용하며 없어도 동일하게 동작한다.

let addNum = new Function('x','y','return x+y');
console.log(addNum(2,5)); // 7

다음과 같이 사용되며, 이 사용법은 일반적은 함수객체 생성방식이 아니며, 클로저를 생성하지 않고 다른 함수의 정의들과는 다르게 동작하는 등 권장하는 방식이 아니다. (클로저가 무엇인지는 모르지만 지금은 넘어가자.)

 

4. 화살표 함수

ES6에서 도입된 함수로 function 키워드 대신에 ( => ) 을 사용하여 간단하게 함수를 선언할 수 있다. 

const addEvent = (x,y) => x+y;
console.log (addEvent(2,5)); //7

이는 사용법도 간단하지만 내부 동작 역시 간단해 졌다는 장점이 있다.

 

'JavaScript Study' 카테고리의 다른 글

JavaScript - #16. 스코프  (0) 2023.08.30
JavaScript - #15. 함수(2)  (0) 2023.08.29
JavaScript - #13. 원시값과 객체(2)  (0) 2023.08.28
JavaScript - #12. 원시값과 객체 (1)  (0) 2023.08.28
JavaScript - #11. 객체 리터럴  (0) 2023.08.27