우리는 많은 프로그램을 사용한다. 프로그램 안에서도 각 기능을 담당하는 것들이 있다. 바로 함수(Function)다. 똑같은 작업을 100번, 1000번 하지 않도록 도와주는 고마운 함수에 대해서 정리해보자.
함수(Function)은 프로그램의 가장 기본 요소이며, 여러 번 사용할 수 있는 서브 프로그램이라고 할 수 있다. 주로 input을 받아 계산하거나 특정 동작을 수행하는 역할을 한다.
// 기본 선언 방법
function doSomething(parameter1, parameter2) {
body ...
return;
}
함수를 선언할 때 함수명은 동사나 명령으로 작성해야 하고, 한 번에 여러 개의 작업을 진행하지 않도록 주의해야 한다. 한 함수는 한 개의 동작을 진행하도록 하자.
// 함수 호출 방법
doSomething(parameter1, parameter2);
함수를 호출하여 사용하고 싶은 경우에는 함수명에 ()
을 붙여서 사용하면 된다. 이 때 ()
안에는 필요한 매개변수를 넣으면 된다. 매개변수가 없는 경우에도 ()
는 함수명 옆에 꼭 붙여야 한다.
// 간단한 예시
function log(message) {
console.log(message);
}
log("Hello@"); // Hello@
매개변수를 사용할 때 주의해야하는 점이 있다. 매개변수가 전달될 때 직접적인 value
을 전달하는 경우와 reference
를 전달하는 경우가 있기 때문이다. 차이점을 기억해두면 좋다.
function changeName(obj) {
obj.name = "coder";
}
const cheoljin = { name: "cheoljin" };
changeName(cheoljin);
console.log(cheoljin); // {name: "coder"}
위의 경우를 보자. cheoljin
의 경우에 const
를 통해서 값을 변경할 수 없도록 선언했음을 알 수 있다. 하지만, changeName(cheoljin)
을 실행하자 이름이 coder
로 변경되었다.
const
로 선언된 cheoljin
이라는 변수에는 {name: "cheoljin"}
이라는 object
의 값이 직접적으로 할당된 것이 아니라 reference
값이 할당되었기 때문이다. 즉, reference
는 변경할 수 없지만 그 reference
를 찾아 도달한 메모리에 있는 내용은 변경할 수 있다는 말이다. 그렇기 때문에 const
를 사용했음에도 내용이 변경될 수 있었다. object
에 대한 자세한 내용은 추후에 정리하려고 한다.
만약, 위의 경우에 cheoljin
에 할당된 값이 "cheoljin"
이라면 어떻게 됐을까?
function changeName(obj) {
obj = "coder";
}
const jini = "cheoljin";
changeName(jini);
console.log(jini); // cheoljin
값이 변경되지 않는다. const
로 선언 된 value
는 변경할 수 없기 때문이다.
Default parameter
// 매개변수를 입력하지 않은 경우에 출력될 값을 미리 정할 수 있음.
function showMessage(message, from = "unknown") {
console.log(`${message} by ${from}`);
}
showMessage("Hi"); // Hi by unknown
Rest parameter
// 정해지지 않은 수의 인자를 배열로 받을 수 있음.
function printAll(...args) {
for (let i = 0; i < args.length; i++) {
console.log(args[i]);
}
}
printAll("dream", "coding", "ellie");
함수(block) 내에서 선언한 변수의 경우에는 함수 안에서만 접근할 수 있다.
let globalMessage = "global"; // global variable
function printMessage() {
let message = "hello";
console.log(message); // local variable
console.log(globalMessage);
// return undefined <- skip!
}
printMessage();
console.log(message);
위에서 함수 printMessage()
를 실행했을 때 console.log(message)
의 경우에는 지역변수인 message
를 같은 함수 안에서 접근했기 때문에 정상적으로 출력이 된다. 또한, console.log(globalMessage)
의 경우에도 전역변수인 globalMessage
에 접근하기 때문에 정상적으로 출력이 된다.
하지만, 마지막의 console.log(message)
의 경우에는 block
밖에 있으므로 지역변수인 message
에 접근하지 못해서 오류메세지가 출력된다.
함수를 사용할 때 우리는 return
을 사용할 수 있다. console.log()
의 경우에는 콘솔 창에 출력을 해줄 뿐이며 실제로 값을 반환하기 위해서는 return
을 사용해야 한다. 만약, return
이 없는 함수의 경우에는 return undefined
가 생략되어 있음을 기억해두자.
빠르게 return
하고 빠르게 exit
를 기억하자.
// bad example
function upgradeUser(user) {
if (user.point > 10) {
// 길고 긴 로직들...
}
}
위의 경우처럼 코드를 작성하게 되면 가독성이 매우 떨어진다. 굳이 조건에 해당하지 않는 경우까지 포함하여 로직을 구성할 필요가 없다.
// good example
function upgradeUser(user) {
if (user.point <= 10) {
return;
}
// 본격적으로 실행하고 싶은 로직들...
}
위의 경우처럼 해당하지 않는 조건들에 경우에는 빠르게 return
을 통해서 빠져나가고 실제로 해당하는 값들에 대해서 로직이 실행될 수 있도록 작성되어 있다. 결과적으로는 같은 동작을 실행한다고 해도 가독성 측면에서 아래가 유리하다.
함수는 기본적으로 statement
으로서 선언할 수 있지만 표현식으로 나타낼 수도 있다.
함수 선언과 표현식의 차이는 생성되는 시점이다. 함수 선언의 경우에는 hoisting을 통해 위로 끌어올려지고 함수 표현식은 JavaScript
의 동작이 해당 위치에 온 경우에 생성된다.
- functions are treated like any other variable
- can be assigned as a value to variable
- can be passed as an argument to other functions.
- can be returned by another function
위의 예시들처럼 함수 표현식을 사용하면 변수에 할당할 수 있고, 다른 함수의 인자로 사용될 수 있으며, 다른 함수의 return
이 될 수도 있다. 일급 함수, 일급 객체에 대한 내용이 궁금하다면 해당 MDN을 자세히 읽어보자.
const print = function () {
// anonymous function
console.log("print");
};
print();
print
라는 변수에 익명 함수를 할당했다. 보통 함수 표현식을 사용하는 경우에는 익명 함수를 사용한다. 이 때, 변수 print
에는 익명함수의 데이터가 직접적으로 들어가는 것이 아니라 reference
가 할당된다.
const printAgain = print;
printAgain();
printAgain
이라는 변수에 print
를 할당하면 동일한 익명함수의 reference
가 할당되고 동일한 결과값을 실행하는 함수로 사용할 수 있다.
function randomQuiz(answer, printYes, printNo) {
if (answer === "love you") {
printYes();
} else {
printNo();
}
}
// anonymous function
const printYes = function () {
console.log("yes");
};
// named function
// better debugging in debugger's stack traces
// recursions
const printNo = function print() {
console.log("no!");
};
randomQuiz("wrong", printYes, printNo);
randomQuiz("love you", printYes, printNo);
함수 표현식을 사용하면 위의 경우처럼 함수의 인자로 함수를 받을 수 있다. 위에서 익명 함수가 아닌 함수 표현식에 함수 명을 따로 기입한 경우가 있는데, 이는 디버깅을 진행할 때 함수명이 기록되도록 해서 편리성을 얻기 위함이고 또한, 재귀함수를 사용할 필요가 있는 경우에도 사용한다.
재귀함수란, 함수가 자신을 재참조하는 경우를 뜻한다. 콜스택이 가득차지 않도록 적절하게 return
을 설정하여야 한다.
내가 가장 마음에 들어하는 화살표 함수이다. 화살표 함수는 항상 익명 함수를 사용하도록 되어있고 function
등의 키워드를 적지 않아도 되기 때문에 매우 편리하다.
// 이렇게 생겼던 코드가
const simplePrint = function() {
console.log("simplePrint");
};
// 이렇게 간단하게 바뀐다.
const simplePrint = () => console.log("simplePrint");
// Fun quiz time❤️
// function calculate(command, a, b)
// command: ( add, substract, divide, multiply, remainder)
function calculate(command, a, b) {
switch (command) {
case "add":
return a + b;
break;
case "substract":
return a - b;
break;
case "divide":
return a / b;
break;
case "multiply":
return a * b;
break;
case "remainder":
return a % b;
break;
default:
return "invalid command";
}
}
console.log(calculate("add", 3, 2));
command
를 인자로 받아 간단한 계산을 할 수 있는 함수를 작성하였다.
참고자료:
드림코딩 by 엘리