본문 바로가기
Programming/JavaScript

함수, 화살표 함수 - [JavaScript 입문 _4]

by Muko 2020. 4. 4.

이번 시간에 공부할 내용은 함수입니다.
내용이 이해가 안될 수 있으나, 절대 좌절하지 마시고 '이런 개념이 있구나~ 무슨 말인지는 모르겠다!' 하고 넘어가셔도 좋습니다. 키워드만 기억하시고, 추후에 연습할 수 있는 코드를 올릴테니 차례대로 따라오면서 익히시다보면 '아~ 그 때 봤던 설명이 이런 내용이었구나!'라고 이해하시는 순간이 오실겁니다. 어렵다고 포기하지 마세요!

5. 함수

함수는 특정 코드를 하나의 명령으로 실행할 수 있게 해주는 기능입니다. 변수도 하나의 이름에 하나 혹은 여러개의 데이터를 넣을 수 있듯이, 함수 또한 여러줄의 코드를 함수의 이름 하나만 적어도 실행할 수 있게해주는 세탁기의 버튼같은 기능입니다.

참조 -  이데일리

위의 사진에서 세탁기를 돌리는데 6가지 모션이 있다고 홍보하는 사진입니다. 우리가 이 세탁기를 돌린다고 상상을 해봅시다. 빨래감을 세탁기에 넣고, 뚜껑을 닫고, 세제를 넣은 뒤에 '시작 버튼'을 누르겠죠? 그러면 세탁기가 알아서 위의 6가지 동작을 하면서 빨래가 돌아가게 됩니다. 이렇게 버튼을 눌렀을 때 6가지 동작을 하라는 것 처럼, 하나의 명령으로 여러 가지 동작을 실행시키는 것이 함수입니다.

function start() { 
  두드리기; 
  비비기; 
  주무르기; 
  흔들기; 
  꼭꼭짜기; 
  풀어주기; 
}

위의 예시를 코드로 한 번 만들어보았습니다. 참 쉽죠?
절대 동작을 영어로 표현을 못해서 한글로 적은 것이 아닙니다. 이해하기 편하시라고 적은 겁니다. 암, 그렇고말고.

​함수라는 단어 자체는 매우 익숙하실 겁니다. 이 함수라는 것이 학교에서 수학시간에 배웠던 함수와 비슷한 개념이거든요. 어떤 입력값이 들어왔을 때 정해진 동작을 수행하고 결과를 반환한다는 개념을 코드를 통해서 이해해보도록 하죠.

// 함수 선언 
// x는 매개변수(parameter) 
function myCalc(x) { 
  const y = x*x + 2*x + 1; // (x+1)^2 
  return y; // 결과로 y를 반환. 
} 
// 함수 호출 
myCalc(4); // 결과: 25. 숫자 4는 인자(argument)

myCalc 함수에 x라는 값이 들어오면, (x+1)의 제곱을 풀어서 쓴 x^2 + 2x + 1 이라는 식을 계산해서 y에 저장하고, 그 y를 반환한다는 코드입니다. 그리고 정의한 myCalc 함수에다가 숫자 4를 넣게되면? 결과값으로 25를 반환하게 되는 것이죠. 이렇게 함수가 어떤 동작을 하는지 정의하는 것을 함수 선언이라고 합니다.

그런데 함수라는 개념을 자바스크립트에서는, 혹은 다른 프로그래밍 언어에서 사용하는 이유는 무엇일까요? 핵심은 우리가 작성한 코드를 재사용할 수 있다는 것입니다. 위의 코드에서 x값에 따라서 다른 결과를 내놓지만, 그 안에서의 동작이 동일한 것, 그리고 이러한 동작을 함수명 하나만으로 다른 곳에서 언제든지 사용할 수 있다는 점에서 함수라는 개념은 엄청난 가치를 가지게 됩니다. 같은 코드를 작성할 필요가 없어지니 생산성이 늘어나니까요! 이렇게 함수를 이용해서 재사용할 수 있다는 특징은 다르게 말하면 함수 자체만 잘 관리하면 프로그램 전체를 관리할 수 있게된다는 의미입니다. 모든 코드가 함수화 되어있고, 무언가 프로그램을 개선하고자 한다고 가정합시다. 그러면 개선하고자 하는 기능과 관련된 함수들을 찾아서, 그 함수의 코드만을 고치기만 하면 됩니다. 또한 개발을 진행하다보면 수 많은 에러와 만나게 되는데요, 이렇게 함수화가 잘 되어있으면 어디서 에러가 발생했는지 찾기도 용이해집니다. 따라서 유지보수하기가 매우 편해집니다.

이렇게 장점이 많은 함수를 어떻게 선언하고 사용하는지 알아보도록 하겠습니다.

function functionName (parameter1, parameter2) {
	const myString = parameter1 + parameter2;
    return myString;
}
functionName('my', ' firstFunction'); // my firstFunction

​함수를 만들 때는(함수를 선언할 때는) function 이라는 키워드를 사용하고, 그 뒤의 괄호 안에 함수에서 어떤 값을 받아올지 정해주는데 이를 매개변수(parameter)라고 합니다. 여기서는 functionName 옆의 괄호 안에 들어가는 parameter1, parameter2가 매개변수가 되는 것이죠. 매개변수라는 말 그대로 정의한 함수를 사용할 때 값을 넣을텐데, 그 넣은 값을 보관할 수 있는 매개체 역할을 하는 변수라는 의미에서 매개변수입니다. 아래에서 functionName('my', 'firstFunction')라고 함수를 사용(함수 호출)하는데 여기서 함수 안에 정의된 myString은 파라미터로 넘어온 두 개의 스트링을 붙인  'my firstFunction'이라는 값을 보관한 뒤, 그 값을 반환하고 있습니다.

​위의 코드에서는 함수에서 반환값을 넘겼는데요, 자바스크립트에서 함수는 반드시 결과를 넘기지 않아도 됩니다. 만약 넘겨야할 경우에는 return 키워드를 사용하면 됩니다. 만약 다음과 같이 return 키워드가 결과를 반환한 뒤에 동작할 코드가 있을 경우에는 이미 return으로 인해 함수가 끝나버렸기 때문에 무시가 됩니다.

function add(a, b) { 
	return a + b; 
	console.log('이 부분이 동작이 될까요?'); 
} 
const result = add(3, 5); 
console.log(result); // 8

이 코드를 보시면 위의 4줄은 add 함수를 정의하는 부분이기 때문에 바로 실행되지 않습니다. 세탁기가 시작 버튼이 눌러져야 비로소 동작을 하듯이, 자바스크립트에서도 마찬가지로 add 함수를 호출해야 비로소 동작하게 됩니다. 그래서 5번째 줄에서 add(3, 5)를 통해서 함수가 실행이 되고, 2번 째 줄에서 3+5의 결과인 8을 반환하게 됩니다. 그런데 이미 결과값을 반환하면서 함수가 종료가 되었으므로, 그 아래에 console.log('이 부분이 동작이 될까요?');은 자연스럽게 무시가 되는거죠.

const alertDate = function() {
    const date = new Date();
    alert(date);
};
alertDate(); // undefined

위와 같이 return이 없는 함수는 자동으로 undefined를 반환합니다. 함수를 호출했을 때 뜨는 알람은 return과 상관없이 코드에 작성한 alert(date)로부터 나온 동작 결과일 뿐입니다. 대신 알람이 뜨고나서 콘솔창을 보면 undefined가 출력되는 것을 확인할 수 있는데, 그게 바로 alertDate 함수의 return 값입니다. 자바스크립트에서 모든 함수는 return을 입력하지 않으면 자동으로 return undefined가 마지막 코드로 동작하게 되어있어서 함수가 끝나게끔 구현되어 있기 때문입니다.

이번에는 매개변수로 숫자나 문자열말고 객체를 받아볼까요?

const sampleFunction = function(object) { 
  const sum = object.val1 + object.val2 + object.val3 + object.val4 + 10000; 
  return sum; 
} 
const myObject = { 
  val1: 1, 
  val2: 10, 
  val3: 100, 
  val4: 1000 
}; 
sampleFunction(myObject); // 11111

현재 함수에 인자로 넘긴 객체는 총 4개의 속성을 가지고 있습니다. 이 객체를 함수에서 모두 더한 값 + 10000을 계산한 결과값을 반환하게 되는데요, 만약 이 인자를 받기위해서 매개변수 하나하나를 모두 적었다고 생각해보세요. 만약 받아야할 매개변수의 수가 20개가 넘어간다면? 함수를 선언하는 것도, 코드를 읽는 것도, 함수를 사용하는 것도 모두 고통스러운 행위가 될 것입니다. 그럴 때 이렇게 객체를 사용하면 하나의 매개변수로 많은 값을 전달할 수 있습니다.

​제가 수학에서 배운 함수와 개념이 비슷하다고 했지만 같다고 하지 않은 이유는, 함수가 결과를 반드시 반환하는 것이 아니기 때문입니다. 자바스크립트에서의 함수는 결과를 필요에 따라 반환 여부를 결정할 수 있습니다. 바로 return 키워드를 이용해서 말이죠!

const alertDate = function() { 
  const date = new Date(); 
  alert(date); 
}; 
alertDate(); // undefined

위와 같이 return이 없는 함수는 자동으로 undefined를 반환합니다. 또한 return이 없기 때문에 처음부터 끝까지 함수에서 정의한 내용을 그대로 동작하게 됩니다. 위의 코드에서는 date 변수에 오늘 날짜를 저장하고, 그 변수에 저장된 값을 alert 하게끔 동작하고 있습니다. 이 사실을 바탕으로 유추해보면 자바스크립트에서는 함수 뒤에 return 키워드가 없으면 자동으로 return undefined가 붙어서 함수를 끝마치게끔 동작한다는 것을 알 수 있습니다.

​추가적으로 첫 시간에 말씀드렸듯이 2015년에 자바스크립트가 제대로 다시 스펙이 정의가되면서 생긴 큰 변화가 바로 화살표 함수입니다. 화살표 함수는 함수를 선언하는 또 다른 문법인 셈인데요, 숫자 두 개를 더하는 아주 간단한 함수를 화살표 함수로 작성해보겠습니다.

const add = (a, b) => { 
  return a + b; 
}; 
add(2, 5); // 7

화살표 함수에서는 function이라는 키워드가 사라진 대신 (매개변수) => {동작 내용}의 형식을 갖추고 있습니다. 그런데 위와 같이 동작 내용(코드 블록) 안에서 바로 return을 하는 경우에는 다음과 같이 줄여서 쓰는 것이 가능합니다.

const add = (a, b) => a + b; 
add(2, 6); // 8

중괄호와 return이 생략된 것을 확인할 수 있습니다. 기존에 function을 써서 만드는 것보다 더 간결하게 짤 수 있는 코드가 많아진 것이죠.

 

정리하면
함수를 만들어서 정의하는 것을 함수 선언,
함수에서 필요한 동작을 끝내고 return 키워드를 만나서 값을 함수 밖으로 내보내는 것을 반환
함수를 사용하는데 필요한 값을 넘기는 것을 인자(argument),
정의된 함수를 사용한다고 코드로 컴퓨터에게 알리는 것을 함수 호출,
함수 호출 시에 넘긴 값을 보관하는 변수를 매개변수(parameter) 라고 합니다.

거기에 덧붙여서 자바스크립트에서의 함수는 일급객체(first-class object)입니다. 여기서 일급 객체란 변수에 저장 가능하고, 함수의 파라미터로 전달 가능하며, 함수의 반환값으로 사용할 수 있고, 어떤 자료 구조에도 저장 가능해야한다는 조건을 모두 만족하는 객체입니다. 따라서 자바스크립트에서 함수는 일급객체이기 때문에 위의 조건에 해당하는 내용이 모두 가능합니다.

 


또한 함수는 변수의 범위(스코프)를 결정합니다.

const x = 100;

const printValue = function(value) {
    const x = 5000;
    return value + x;
}
const printValue2 = function(value) {
    return value + x;
}
printValue(1); // 5001
printValue2(1); // 101

위의 코드를 보면, 먼저 x = 100이라고 변수를 선언하고, printValue라는 함수를 선언한 것을 확인할 수 있습니다. 여기서 문제가 될만한 요소는 함수 안에서도 const x = 5000;이라고 변수 선언을 했다는 것이죠. 함수는 변수의 범위를 결정하다고 말씀드렸듯, 함수 안에 작성된 const x는 함수 밖에 있는 const x와는 별개의 변수로 존재하게 됩니다. 함수가 하나의 새로운 영역이 되기 때문이죠. 그래서 printValue(1)은 5001이라는 결과값을 반환하게 됩니다.

반면 printValue2의 경우에는 따로 변수 x에 대한 선언이 함수 내에 작성되어 있지 않습니다. 그런데 x라는 변수를 반환할 때 사용하고 있죠. 이 때는 이미 밖에서 선언한 변수 x를 가져와서 값을 계산하는데 사용한다는 의미입니다. 만약 동일한 이름의 변수가 함수 내에 작성되어 있지 않다면, 밖에서 선언한 변수나 함수를 그대로 사용할 수 있습니다. 변수와 함수의 범위가 더 넓기 때문이죠. 어떤 함수의 내부, 혹은 블록의 안에서 작성한 변수나 함수의 경우에는 밖에서 선언한 것들 보다 범위(스코프)가 좁다고 해석할 수 있습니다. 따라서 코드를 작성할 때 각 변수와 함수의 스코프를 유의해야합니다.

 


 

위에서 함수를 만드는 다양한 방법을 소개했는데요, 여기서 조금 더 나아가, 함수를 만드는 방법에 따라 함수 선언식, 함수 표현식, 즉시실행함수이라는 개념에 대해서 알아보도록 하겠습니다.

1. 함수 선언식

// 함수 선언식 (function declaration)
function addTwoNumbers(val1, val2) {
    return val1 + val2;
}

함수 선언식으로 정의된 함수는 Javascript 인터프리터가 스크립트가 로딩되는 시점에 바로 초기화됩니다. 그래서 코드에서의 위치에 상관없이 작성해도 동작에 영향을 주지 않으며, 심지어 함수를 호출하는 부분보다 아래에 코드를 작성하더라도 에러없이 동작합니다. 이는 자바스크립트가 실제로 작성된 코드(script)를 실행하기 전에 전역에 선언된 변수들과 함수 선언문을 찾고, 변수들과 함수들을 생성해서 메모리에 올리기 때문입니다. 이러한 전처리가 끝난 뒤에 script가 실행되기 때문에 함수 선언식의 위치와 상관없이 프로그램이 동작하게 되는 것이죠.

2. 함수 표현식

const addTwoNumbers = function(val1, val2) {
    return val1 + val2;
}

함수 표현식은 변수를 선언할 때 함수로 초기화하는 방식을 함수 표현식이라고 합니다. 이러한 함수 표현식은 실제 script 코드가 동작하면서 실행하는 작업의 흐름이 이렇게 작성한 함수에 도달했을 때 비로소 함수를 메모리에 올립니다. 따라서 코드 실행 흐름이 함수에 도달하고 나서부터 함수를 호출(사용)할 수 있게 됩니다. 이렇게 코드 실행 흐름에 따라서 함수가 생성되고 사용되는 것을 다르게 표현하면 '런타임할 때에 해석되고 실행한다'라고 말할 수 있습니다.

3. 즉시실행함수

자바스크립트에서 함수를 실행하는 방법은, 함수를 호출하는 것 외에도 즉시실행함수로 함수를 정의하는 방법이 있습니다. 굳이 함수를 정의해서 변수에 저장하거나, 함수 선언식을 이용해서 메모리에 가지고 있는 상태에서 실행하기 보다는, 딱 함수가 필요한 영역에서 실행시켜버리고 메모리에 싣지 않는 것이 바로 즉시실행함수입니다. 예제로 확인해보도록 하겠습니다.

const myName = 'muko';

const printName = (name) => {
    console.log('제 이름은: ', name, ' 입니다.');
};
printName(myName);

((name) => {
    console.log('제 이름은: ', name, ' 입니다.');
})(myName);

위에서 작성한 함수 두개는 같은 동작을 수행합니다. 함수표현식으로 작성한 printName 함수는 변수에 함수를 저장하고, 함수 호출을 통해 코드를 실행하는 과정을 거치지만, 즉시실행함수를 사용하면 저장이라는 개념없이 즉시 실행 가능합니다. 코드상에서의 차이점은 함수를 괄호()로 감싼다는 것입니다.

 

다음 시간에는 연산자에 대해서 알아보겠습니다.

댓글0