First Step

함수

함수는 프로그램 안의 미니 프로그램처럼 특정 일을 처리한느 명령어들을 묶어놓은 것이다. 함수는 하나의 작업을 해야 하고, 그 작업과 관련딘 모든 명령어들이 전부 함수 안에 포함되어야 한다.

1. 함수의 구조

언어마다 문법은 약간 다를 수 있지만 기본 구조는 거의 같다. 함수는 함수를 선언하는 특정 키워드로 시작한다. 자바스크립트 같은 경우에는 function이라는 키워드를 사용한다. function뒤에 함수의 이름이 오는데, 함수의 이름은 함수가 수행하는 작업을 가리키는 이름으로 정해야 한다. 그리고 함수의 인자들도 그 이름과 함께 정의되고, 마지막으로 실행될 코드가 들어가는 함수의 본문이 온다. 만약 반환해야할 값이 있다면 return키워드를 통해 값을 반환하면 된다.

function 함수이름(인자) {
  함수본문
  ruturn 반환값
}

1.1 정의

함수를 정의하는 것은 그 함수의 본문에 있는 코드를 언젠가 사용할 것임을 선언하는 것이다. 함수를 선언했다고 함수의 본문이 자동으로 실행되는 것은 아니다. 만들어진 함수를 호출할 때 비로소 선언해놓은 함수의 본문이 실행된다. 함수의 이름에는 함수가 어떤 기능을 해야하는지 명시하는 것이 중요하다. 만약 함수의 이름을 정하기가 어렵다면, 함수의 기능이 명확하지 않은 것이다. 함수 이름은 *함수가 수행하는 작업이 무엇인가?*에 대한 답이 되어야 한다. 즉, 함수를 정의하기 전에 내가 만들 함수가 어떤 기능을 할 것인지 명확히하는 것이 중요하다.

1.2 호출

선언해놓은 함수의 본문을 사용하는 것을 말한다. 함수의 본문은 함수가 호출(invocation)되기 전까지는 실행되지 않는다. 함수를 호출하는 방법은 거의 모든 언어가 같다. 먼저 함수의 이름이 오고 다음에 소활호 한쌍이 오는 방식이다. 소괄호 안에는 인자가 올 수도 있고, 인자를 넘겨주지 않을 수도 있다. 자바스크립트에서 자주 사용하는 console.log() 역시 하나의 함수이다.

1.3 인자

함수는 인자를 받도록 만들 수 있다. 인자는 함수로 전달되어 함수의 동작을 결정하는데 사용된다. 예를들어 console.log는 인자로 콘솔에 출력될 문자열을 받는다. 인자를 통해 함수를 좀더 융통성있게 만들어 줄 수 있다(상황에 따라 다양한 값을 넣을 수 있기 때문).

// 인자 vs 파라미터
function helloJs(string) {
  console.log(string);
}

helloJs('hi');

함수를 선언할 때 함수 내부에서 사용할 요소를 받는 것을 파라미터,
만들어진 함수를 사용할 때 함수내부로 데이터를 넘겨주는 것을 인자라고 한다.

즉, string => 파라미터, 'hi'=>인자 이다.

파라미터에 대해 조금더 자세하게 말하자면,
파라미터는 특별한 형태의 변수로 함수 안에서 인자의 값을 저장하는 익을 한다고 볼 수 있다.

1.4 반환(리턴)

인자가 입력이라면 반환값은 출력이다. 함수 중에는 무엇을 하는 것보다 무엇을 받는 것이 목적인 경우가 있는데, 이런 목적의 함수의 경우 반환값이 없는 경우도 있다. 반면 반환해야하는 값이 있는 함수라면 반드시 return문이 있ㅇ어야 한다. 자바스크립트에서는 return이 없을 경우 undefined를 반환한다.

return문은 언제나 함수 본문의 마지막 명령이다. 함수 내부에서 return을 만나면, 그 자리에서 함수가 종료되고 정해진 값을 반환한다. return문 뒤에 어떠한 코드가 있더라고, 그 뒤의 코드는 실행되지 않고 함수는 종료된다.

1.5 콜스택

함수는 다시 다른 함수를 호출할 수 있다. 그리고 함수 내부에서 호출된 함수는 다시 다른 함수를 호출할 수 있다. 함수 안에서 다른 함수들이 호출될 때 그 함수 목록들을 *콜 스택(Call stack)*이라고 한다. 새로운 함수가 호출되면 그 함수가 콜 스택의 맨 위로 올라간다. 함수가 종료되면, 콜 스택에서 그 함수가 제거된다. 콜스택 참고자료

function first() {
  console.log('첫번째 실행 함수');
  console.log('두번째 실행할 함수를 부른다.');
  second();
}

function second() {
  console.log('두번째 실행 함수');
  console.log('세번째 실행할 함수를 부른다.');
  third();
}
function third() {
  console.log('세번째 실행 함수');
}
callstack

2. 함수 사용의 이점

2.1 코드 캡슐화

함수의 주된 기능 하나는 바로 코드를 정리하는 것이다. 함수는 여러 명령어들을 하나로 깔끔하게 묶어서(캡슐화) 하나의 명령어로 호출할 수 있도록 할 수 있다. 이를 코드 캡슐화(code encapsulation)라고 한다. 이때 코드 구조 측면에서 함수 분문의 멍령어들은 모두 함수와 관계된 것이어야 한다.

2.2 코드 재사용

함수는 만들어 놓으면 필요할 때마다 몇 번이고 반복해서 사용할 수 있다. 물론 재사용 가능한 함수를 만들기 위해서는 문제를 생각하는 방식을 바꿀 필요가 있다. 눈앞에 있는 문제만 보는 것이 아니라, 현재 눈앞에 있는 문제와 같은 형식의 문제들을 범용적으로 해결하는 방법을 생각해야 한다. 코드 재사용은 반복을 줄여준다. *DRY(Don't Repeat Yourself)*개념은 프로그래밍에서 자주 등장하는데, 반복을 줄이는 코드를 작성하자는 것이다. 잘 정의된 함수는 반복을 줄이는 해답이 될 것이다.

2.3 분할 정복

함수를 사용해 긴 코드를 분할할 수 있다. 모든 기능들이 분할없이 하나로 되어있다면 오히려 유지, 보수에 어려움을 겪을 수 있다. 그래서 각 기능을 함수로 만들어서 기능별로 관리한다면 개발 및 관리에 도움이 될 것이다. 또한 코드를 분리해놓고 살펴보면 불필요한 코드를 제거할 수 있다.

3.범위(Scope)의 문제

여기서 말하는 범위는 변수와 관련이 있다. 변수는 값을 참조하는 것으로, 문자열이든 불리언(Boolean) 혹은 객체가 될 수 있다. 프로그램이 실행될 때 변수를 만나면 실행 환경은 그 변수의 이름을 이용해 연결된 값을 찾아낸다. 변수의 이름을 이용해 연결된 값을 찾을 때 **범위(Scope)**의 개념이 나온다. 실행 환경이 변수의 값을 찾는 범위를 말한다. 만약 변수가 함수 안에 선언되어있다면, 실행 환경은 그 이름의 변수를 함수 안에서만 찾을 수 있다. 함수 안에 선언된 변수는 다른 함수에서 사용할 수 없다.

var Name = "코딩";
function sayName() {
  // 함수 안에 함수 밖의 변수 Name과 같은 이름의 변수를 선언
  var Name = "프로그래밍";
  console.log("My Name is: ", Name);
}

function sayFullName() {
  // 함수 안에 함수 밖의 변수 Name과 같은 이름의 변수를 선언
  var Name = "프로그래밍";
  var lastNmae = "자바스크립트";
  console.log("My Name is in sayFullName: ", Name);
  console.log("My LastName is in sayFullName: ", lastNmae);
}

sayName();
sayFullName();

console.log(Name);
console.log(lastNmae);

위 함수를 실행시켜보자. 실행환경은 먼저 함수의 밤위에서 변수를 찾고 그 후에 그 밖의 범위에서 값을 찾는다. lastNamesayFullName 함수 안에서는 값을 갖지만, sayFullName밖에서 사용될 때는 오류가 발생한다. lastName이 선언된 범위 내에서만 사용가능하기 때문이다.

3.1 변수 검색이 이루어지는 원리

코드에서 변수를 사용하면, 런타임 환경이 그 변수의 값을 찾아야 한다. 런타임 환경은 가장 먼저 현재의 범위 안에서 그 값을 찾으려 시도한다. 만약 그 이름이 현재 범위에 존재하지 않으면 현재 범위의 상위 범위에서 검색을 한다. 이 과정은 전역 변수의 범위를 검색할 때까지 계속된다. 만약 전역 범위에도 검색되지 않으면 에러가 발생한다(변수 이름이 없기 때문).

3.2 전역변수, 지역변수

전역(Global)변수는 어디서든 접근이 가능한 변수를 말하낟. 일반적으로 전역 변수는 함수 바깥에 정의한다. 어디서든 접근이 가능하는 면에서 편리하지만 단점도 있다. 전역 변수를 너무 많이 사용할 경우 코드에 예상치 못한 에러가 발생할 수 있다.

var Name = "코딩";
function sayName() {
  // 함수 안에 함수 밖의 변수 Name과 같은 이름의 변수를 선언
  Name = "프로그래밍";
  console.log("My Name is: ", Name);
}

sayName();
console.log("My Name is in sayFullName: ", Name);

위와 같은 코드의 경우, Name은 함수 안과 밖 모두 프로그래밍이다. 이는 함수 내에서 var를 사용한 것이 아닌 이미 선언된 변수에 새로운 값을 할당했기 때문이다. 전역변수는 다른 코드가 쉽게 그 값을 덮어쓸 수 있다. 프로그램 실행에 중요한 값이 전역 변수에 저장되어 있다면, 다 른 어떤 파일도 그 값을 바꿀 수 있다는 것과 그것을 알아챌 수도 없다는 것을 알아야 한다. 따라서 전역변수의 사용을 줄일수록 코드 관리가 편해진다.

지역(Local)변수는 함수 안에서만 접근 가능한 변수다. 함수가 실행을 마치면 지역 변수들도 모두 사라진다. 함수 안에 변수를 선언하면 다른 곳에 같은 이름의 변수가 선언되어있는지 걱정하지 않아도 된다. 같은 이름의 변수가 전역변수에 선언되어있더라도, 함수 내부에 선언된 변수에 우선권이 있다(그렇다고 같은 이름을 쓰는 것이 좋다는 것은 아니다).

4. 정리

함수는 코드를 잘 관리할 수 있고, 효과적으로 사용할 수 있으며 재사용 할 수 있게 해준다.

  • 함수의 구조
  • 함수 사용의 이점
  • 범위

출처: 다시시작하는 프로그래밍(2015, 인사이트)