[Javascript] 자바스크립트에서의 함수(함수 표현식, 익명함수, Rest 연산자...)
모든 프로그래밍 언어에서 함수가 중요하듯 자바스크립트에서도 함수는 중요한 개념이다.
이러한 함수를 자바스크립트 관점에서 바라보고, 몇몇 특이점을 정리해볼려한다.
1. 함수? 메서드? 항상 헷갈리는 용어
2. 함수의 정체
3. 함수를 정의하는 두가지 방식
4. 함수를 표현하는 다양한 방식
5. Rest 연산자
1. 함수? 메서드? 항상 헷갈리는 용어
대부분 함수 = 메서드라 여기고 혼용한다.
하지만 함수와 메서드는 다른것이다.
객체에는 보통 키-값 쌍으로 데이터를 저장하는데, 여기에 함수도 저장할 수 있다.
const person = {
dummy: function dummyFn() {
console.log("messi");
},
};
person.dummy();
이런식으로 객체에 저장된 함수를 메서드라 한다.
-> 이러한 함수들은 객체명.함수명()으로 사용할 수 있다.
ex) document.getElementById("start-game-btn");
2. 함수의 정체
결론부터 말하면 함수는 객체다.
function dummy() {
console.log("함수는 객체다");
}
console.dir(dummy);
3. 함수를 정의하는 두가지 방식
함수를 정의하는 방식에는 대표적으로 2가지가 존재한다.
A. 함수 선언
B. 함수 표현식
A. 함수 선언
함수 선언이란 function 함수명 () {} 이런식으로 함수를 정의하는 방법을 뜻한다.
함수 선언 방식으로 함수를 정의하면 함수는 전역 스코프에 저장되어 스크립트 어디서나 접근 및 호출이 가능하다.
또한, 스크립트 어느 위치에 정의하여도, 자바스크립트가 자동으로 함수를 스크립트 맨위로 호이스팅하여 초기화한다.
-> 즉, 함수를 선언하기도 전에 호출하는 것이 가능
dummyFn2();
function dummyFn2() {
console.log("스크립트 맨아래 정의되어있는 함수");
}
위 처럼 사용하여도 오류가 발생하지 않는다.
B. 함수 표현식
함수 표현식이란 함수를 변수(or상수)에 할당한 함수를 뜻하고, 함수 자체가 전역스코프에 저장되는것이 아닌 함수가 할당되어있는 변수가 전역스코프에 저장되어 변수를 통해 함수를 참조할수있게된다.
함수 표현식 또한 호이스팅이 적용되지만, 상수가 정의(초기화)되지 않은 상태로 호이스팅됨
-> 즉, 상수가 정의되기 전까지는 함수를 호출할수없음
위의 코드처럼 사용하면 오류가 발생한다.
4. 함수를 표현하는 다양한 방식
function dummy() {
console.log("함수는 객체다");
}
위의 코드처럼 함수를 정의할때는 function 함수명() {}의 형태를 주로 사용해왔다.
하지만 자바스크립트에는 다른 함수 정의 방식이 존재한다. 바로 익명함수다.
익명함수는 함수명이 존재하지 않는 함수를 뜻하고, 특정 상황에서 사용 가능하다.
- 3번에서 살펴본 함수 표현식에서 익명함수(함수명이 존재하지 않는..)를 사용할수있다.
- 이벤트리스너 or 함수에서 또 다른 함수를 참조할때도 사용할수있다.
-> 이 방법은 함수가 다른곳에서는 활용되지않고 정의된 곳에서만 사용될때 주로 활용
const start = function () {
console.log("함수 표현식에서의 익명함수");
};
startGameBtn.addEventListener("click", function () {
console.log("함수내에서의 익명함수");
});
*참고
함수내에서 바로 익명함수를 작성하는 것은 별로 좋지않다.
왜냐하면 오류 발생시 어떤 함수에서 오류가 발생했는지 찾기 어렵기때문(오류 로그에 함수명이 나타나질 않는다.)
5. Rest 연산자
자바스크립트는 기본인자라는 기능으로 인해 매개변수의 개수가 인수보다 많아도 오류는 발생하지 않는다.
(기본인자 설명: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Default_parameters)
반대로 매개변수의 개수가 인수보다 적으면 어떻게 될까? 또는 동적인 인수에(몇개가 전달될지 미리 알수없는 상황)는 어떻게 대응하면될까?
간단한 해결방법은 인수를 배열로 설정하여 넘기고, 받는 매개변수도 배열이 되면 해결된다.
-> 하지만 이 방법은 인수를 무조건 배열로 설정해야한다는 문제점이 발생한다.
-> 그렇다면 배열을 활용한 다른 방법으로 해결해주는 기능은 없을까?
그것이 바로 Rest 연산자이다.
Rest 연산자는 const sumUp = (...number) => {~~~} 매개변수 앞에 … 을 찍는 형태이다
(스프레드 연산자와 비슷하지만, Rest 연산자는 매개변수 위치에 사용되고, 스프레드 연산자는 객체나 배열에 사용된다는 차이점이 있다.)
Rest 연산자는 동적인(무수한?) 인자들을 받아 배열을 설계한다
const sumUp = (...number) => {
let sum = 0;
for (const num of number) {
sum += num;
}
console.log(number);
// 출력결과 => [1, 2, 3, 4, 5, 6]
return sum;
};
console.log(sumUp(1, 2, 3, 4, 5, 6));
*Rest 연산자 사용시 주의점
a. Rest 연산자는 항상 매개변수의 마지막에 와야한다
(Rest 연산자 앞에 다른 매개변수가 있는것은 가능)
b. 매개변수에는 오직 하나의 Rest 연산자만 있어야한다(두개 이상의 Rest 연산자 불가능)
*참고
Rest 연산자는 ES6부터 도입된 기능이다. 그럼 이전에는 위와같은 문제를 어떻게 해결했을까?
function 키워드를 사용하면 arguments라는 키워드를 사용할수있는데, 이는 인자들을 배열로 만드는 키워드이다
이러한 방식으로 해결해왔다.
const sumOld = function () {
let sum = 0;
for (const num of arguments) {
sum += num;
}
return sum;
};
하지만 Rest 연산자가 나온이상 arguments 보다는 Rest 연산자를 활용하는 것이 바람직하다.