15. 함수

함수

함수 선언

  • function 키워드, 함수 이름, 괄호로 둘러싼 매개변수를 차례로 써주면 함수를 선언할 수 있다.
function name(parmeter1, parameter2, ... parameterN) {
// 함수 본문 
}

// 새롭게 정의한 함수 이름 옆에 괄호를 붙여 호출할 수 있다
function showMessage() {
	alert ('안녕하세요!');
}

showMessage(); // 함수 호출
  • 함수의 주요 용도 중 하나는 ‘중복 코드 피하기’

    위의 예시에서 alert 창에 보여줄 메시지를 바꾸거나 메시지를 보여주는 방식 자체를 변경하고 싶다면,

    함수 본문 중 출력에 관여하는 코드만 수정하면 된다.

지역 변수

함수 내에서 선언한 변수인 지역 변수(local variable)는 함수 안에서만 접근할 수 있다.

function showMessage() {
	let message = '안녕하세요!' // 지역 변수

	alert (message);
}

showMessage(); // 안녕하세요! 출력

alert (message); // ReferenceError: message is not defined

외부 변수 (= 전역변수)

함수 내부에서 함수 외부의 변수인 외부 변수(outer variable)에 접근할 수 있다.

let userName = 'John';

function showMessage() {
	let message = 'Hello,' + userName;
	alert(message);
}

showMessage(); // Hello, John

---

let userName = 'John';

function showMessage() {
	userName = 'Bob'; // 외부 변수를 수정

	let message = 'Hello,' + userName;
	alert (message);
}

alert (userName); // 함수 호출 전이므로 John 출력

showMessage();

alert (userName); // 함수에 의해 Bob으로 값이 바뀜

위의 예시처럼 함수에서 외부 변수를 수정할 수도 있다.

  • 외부 변수는 지역 변수가 없는 경우에만 사용할 수 있다.

    함수 내부에 외부 변수와 동일한 이름을 가진 변수가 선언되었다면, 내부 변수는 외부 변수를 가린다.

    ⇒ 동일한 이름의 변수를 선언하면 외부 변수는 내부 변수에 가려져 값이 수정되지 않는다.

let userName = 'John';

function showMessage() {
	let userName = 'Bob'; // 같은 이름을 가진 지역 변수 선언

	let message = 'Hello,' + userName;
	alert (message);
}

showMessage(); // 함수는 내부 변수인 userName만 사용

alert (userName); // 기존 외부 변수의 바뀌지 않은 값 'John' 출력

매개변수

  • 임의의 데이터를 함수 안에 전달할 수 있다
function showMessage(from, next) { // 인자 : from, text 
	alert (from + ': ' + text);
}

showMessage ('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage( ('Aknn', "What's up?"); // Ann: Wha's up? (**)

위의 예시에서 함수 showMessage는 매개변수 from과 text를 가진다.

  • 매개변수는 함수 선언 방식 괄호 사이에 있는 변수 (선언 시 쓰이는 용어)
  • 인수는 함수를 호출할 때 매개변수에 전달되는 값 (호출 시 쓰이는 용어)

기본값

  • 함수 호출 시 매개변수에 인수를 전달하지 않으면 그 값은 undefined가 된다.
showMessage ('Ann'); // Ann: undefined

매개변수에서의 예시(showMessage(from, text))는 매개변수가 두지만, 위와 같이 인수를 하나만 넣어서 호출할 수 있다.

두 번째 매개변수에 값을 전달하지 않았기 때문에 text엔 undefined가 할당된다.

  • 매개변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면

    함수를 선언할 때 ‘=’를 사용해 ‘기본값 (default value)’를 설정해주면 된다.

function showMessage (from, text = 'no text given') {
	alert (from + ': ' + text);
}

showMessage('Ann'); // Ann: no text given
showMessage('Ann', undefined); // Ann: no text given
  • 함수 표현식도 기본값으로 설정할 수 있다.
function showMessage (from, text = anotherFunction()) {
	// anotherFunction()은 text값이 없을 때만 호출
	// anotherFunction()의 반환 값이 text의 값이 된다
}

매개변수 기본값을 설정할 수 있는 또 다른 방법

  • 함수를 선언할 때가 아닌 함수 선언 후에 매개변수 기본값을 설정하는 것이 적절한 경우도 있다.

    이런 경우엔 함수를 호출할 때 매개변수를 undefined와 비교하여 매개변수가 전달되었는지 확인

function showMessage(text) {
	// ...
	if (text === undefined) { // 매개변수가 생략되었다면
		text = '빈 문자열';
	}

	alert (text);
}

showMessage(); // 빈 문자열
  • if문을 쓰는 것 대신 논리 연산자 || 를 사용할 수도 있다.
function showMessage(text) {
	text = text || '빈 문자열';
	...
}
  • 외에도 nullish 병합 연산자 ?? 를 사용하면 falsy로 평가되는 값들을 일반 값처럼 처리 가능
function showCount(count) {
	alert(count ?? 'unknown');
}

showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown

반환 값

  • 함수를 호출했을 때 호출한 곳에 특정 값을 반환하게 할 수 있다. ⇒ 반환 값(return value)
function sum(a, b) {
	return a + b;
}

let result = sum(1, 2);
alert(result); // 3

실행 흐름이 return을 만나면 함수 실행은 즉시 중단되고 함수를 호출한 곳에 값을 반환

  • 함수 하나애 여러 개의 return문이 올 수도 있다.
function checkAge(age) {
	if (age >= 18) {
		return true;
	} else {
		return confirm('보호자의 동의를 받으셨나요?');
	}
}

let age = prompt('나이를 알려주세요', 18);

if (checkAge(age)) {
	alert('접속 허용');
} else {
	alert('접속 차단');
}
  • return만 명시하는 것도 가능하다. 이런 경우 함수는 즉시 종료
function showMovie(age) {
	if (!checkAge(age)) {
		return;
	}

	alert('영화 상영'); // 실행되지 않음
	// ...
}

ℹ️ return문이 없거나 return만 있는 함수는 undefined를 반환

function doNothing() {}
alert( doNothing() === undefined ); // true

function doNothing() {
  return;
}
alert( doNothing() === undefined ); // true

⚠️ 자바스크립는 return문 끝에 세미콜론을 자동으로 넣기 때문에 return과 값 사이에 줄을 삽입하면 안 된다.

함수 이름짓기

  • 코드를 읽는 사람이 함수 이름만 보고도 함수가 어떤 기능을 하는지 힌트를 얻을 수 있도록 간결하고 명확하게
  • 함수가 어떤 동작을 하는지 축약해서 설명해 주는 동사를 접두어로 붙여쓴다.
  • ex)

    • ‘get…’ :
    • ‘cacl…’
    • ‘create…’
    • ‘check…’
showMessage(..)     // 메시지를 보여줌
getAge(..)          // 나이를 나타내는 값을 얻고 그 값을 반환
calcSum(..)         // 합계를 계산하고 그 결과를 반환
createForm(..)      // form을 생성하고 만들어진 form을 반환
checkPermission(..) // 승인 여부를 확인하고 true나 false를 반환

ℹ️ 함수는 동작 하나만 담당해야 한다.

함수 == 주석

함수가 길어지면 함수를 잘게 쪼갤 때가 되었다는 신호

  • 함수를 간결하게 만들면 테스트와 디버깅이 쉬어진다
  • 함수 그 자체로 주석의 역할까지 한다
// <수정 전>
function showPrimes(n) {
  nextPrime: for (let i = 2; i < n; i++) {

    for (let j = 2; j < i; j++) {
      if (i % j == 0) continue nextPrime;
    }

    alert( i ); // 소수
  }
}

// <수정 후>
function showPrimes(n) {

  for (let i = 2; i < n; i++) {
    if (!isPrime(i)) continue;

    alert(i);  // a prime
  }
}

function isPrime(n) {
  for (let i = 2; i < n; i++) {
    if ( n % i == 0) return false;
  }
  return true;
}

요약

함수 선언 방식으로 함수를 만들 수 있다.

function 함수이름 (복수의, 매개변수는, 콤마로, 구분) {
	// 본문
}
  • 함수에 전달된 매개변수는 복사된 후 함수의 지역변수가 된다.
  • 함수는 외부 변수에 접근할 수 있지만, 함수 외부에서 함수 내부의 지역변수에 접근하는 건 불가능
  • 함수는 값을 반환할 수 있고, 값을 반환하지 않는 경우는 반환 값이 undefined가 된다.
  • 함수 이름은 함수가 어떤 동작을 하는지 설명할 수 있도록 간결하고 명확해야 한다.
  • 함수는 동작을 수행하기 때문에 이름이 주로 동사이다.
@oxlzlo
Front-End Developer