트랙
/
JavaScript
JavaScript
/
연습 문제
/
라자냐 마스터
라자냐 마스터

라자냐 마스터

학습 연습 문제

소개

함수는 어떤 작업을 수행하기 위해 사용되는, 잘 정리된 재사용 가능한 코드 블록이에요. JavaScript에서 함수를 정의하는 방법은 여러 가지가 있어요. 여기에서는 _함수 선언_과 _함수 표현식_을 살펴봐요. 화살표 함수 같은 다른 방법은 다른 개념에서 다뤄요.

함수 선언

JavaScript에서 함수를 정의하는 표준적인 방법은 _함수 선언_이며, 함수 정의 또는 _함수 문_이라고도 해요.

함수 선언은 function 키워드, 함수 이름, 그리고 괄호 안에 쉼표로 구분한 매개변수 목록으로 이루어져요. 그 뒤에는 중괄호로 감싼 함수 본문(함수가 하는 일을 정의하는 문의 모음)이 와요.

function someName(param1, param2, param3) {
  // ...
}

JavaScript에서는 함수 이름을 쓰고 그 뒤에 인자를 담은 괄호를 붙여서 함수를 호출해요.

someName(arg1, arg2, arg3);

매개변수

함수 본문 안에서 매개변수를 다룰 때는 부작용이 생길 수 있다는 점을 염두에 두세요.

  • 원시 데이터 타입의 값은 _불변_이에요. 함수 본문에서 인자에 어떤 일이 일어나도 원래 값은 영향을 받지 않아요.
  • 다른 모든 값(객체, 배열, 함수)은 재할당해도 원래 값에 영향을 주지 않아요. 하지만 그런 인자를 수정하면(예를 들어 객체에 키를 추가하면) 넘겨받은 원래 값도 함께 수정돼요.

JavaScript에서는 기본적으로 함수 선언에 정의된 모든 매개변수가 선택 사항이에요. 매개변수보다 적은 수의 인자를 넘기면 빠진 인자는 함수 안에서 undefined가 돼요. Null과 Undefined를 참고하세요. 많은 경우 undefined보다 더 적절한 기본값을 지정하는 게 좋아요. 이때 함수 정의에서 기본 매개변수를 직접 지정하면 돼요.

function someName(param1 = defaultValue1, param2 = defaultValue2) {
  // ...
}

return 문

return 문은 함수 실행을 끝내고 함수를 호출한 쪽에 반환할 값을 지정해요. 함수는 여러 개의 return 문을 가질 수 있어요.

function checkNumber(num) {
  if (num === 0) {
    return 'You passed 0, please provide another number.';
  }

  return 'Thanks for passing such a nice number.';
}

함수의 반환값은 변수에 저장할 수 있어요.

function sum(x, y) {
  return x + y;
}

const total = sum(5, 10);
// => 15

값을 return하지 않거나 return 문이 없는 함수의 결과는 undefined예요. JavaScript에는 암묵적인 return이 없어요.

function nakedReturn(a) {
  a * 2;
  return;
}

nakedReturn(1);
// => undefined

function noReturn(a) {
  a * 2;
}

noReturn(1);
// => undefined

JavaScript에서는 정확히 하나의 값만 반환할 수 있어요. 더 많은 정보를 전달하고 싶다면 먼저 그것을 하나로 합쳐야 해요. 보통 객체나 배열로 합쳐요.

function divide(a, b) {
  return {
    quotient: Math.floor(a / b),
    remainder: a % b,
  };
}

함수 표현식

함수 선언은 독립된 문이에요. 하지만 때로는 다른 표현식의 일부로 함수를 정의하는 게 도움이 돼요. 예를 들어 할당식에서, 함수 매개변수(콜백)로, 또는 객체의 값으로 정의할 수 있어요. 이때 함수 표현식을 사용해요. 문법은 함수 선언과 같아요. 다만 함수 이름을 생략해 _익명 함수_를 만들 수 있어요.

const someFunction = function (param) {
  // ...
};

someOtherFunction(function (param) {
  // ...
});

const obj = {
  someFunction: function (param) {
    // ...
  },
};

지침

이 연습 문제에서는 좋아하는 요리책에 나오는 근사한 라자냐를 준비하고 요리하는 일과 관련된 코드를 조금 더 작성해 볼 거예요.

과제는 다섯 개예요. 첫 번째는 요리 자체에 관한 것이고, 나머지 네 개는 완벽한 준비에 관한 거예요.

1. 라자냐가 다 됐는지 확인하기

라자냐를 오븐에 넣었을 때는 이미 꺼내도 되는지 아닌지 알고 싶어요. 라자냐가 오븐에서 타지 않도록 보통 타이머를 맞춰 놓아요. 그런데 가끔은 타이머 맞추는 걸 잊어버리기도 해요.

타이머에 남은 시간을 분 단위로 매개변수로 받는 cookingStatus 함수를 작성해요. 이 함수의 결과는 세 가지예요.

  • 타이머가 0을 가리키면 'Lasagna is done.'을 반환해야 해요.
  • 타이머가 다른 숫자를 가리키면 결과는 'Not done, please wait.'여야 해요.
  • 타이머 값 없이 함수를 호출하면 결과는 'You forgot to set the timer.'여야 해요.

타이머는 0보다 작은 값을 가리키는 일이 없어요.

cookingStatus(12);
// => 'Not done, please wait.'

cookingStatus();
// => 'You forgot to set the timer.'

2. 준비 시간 예상하기

다음에 만들 라자냐를 위해, 요리를 즐길 수 있도록 시간을 충분히 확보해 두고 싶어요. 라자냐에 들어갈 모든 층은 이미 계획해 두었어요. 이제 그것을 바탕으로 준비에 얼마나 걸릴지 예상하고 싶어요.

층의 배열과 층당 평균 준비 시간(분)을 받는 preparationTime 함수를 구현해요. 이 함수는 층의 개수를 바탕으로 전체 준비 시간의 예상값을 반환해야 해요. 평균 준비 시간을 제공하지 않고 함수를 호출하면 2분으로 가정해야 해요.

const layers = ['sauce', 'noodles', 'sauce', 'meat', 'mozzarella', 'noodles'];
preparationTime(layers, 3);
// => 18

preparationTime(layers);
// => 12

3. 필요한 면과 소스의 양 계산하기

시간을 확보하는 것 외에도, 꿈에 그리던 라자냐를 만들 만큼 소스와 면이 충분한지도 확인하고 싶어요. 라자냐에 면 층이 하나 있을 때마다 면 50그램이 필요해요. 라자냐에 소스 층이 하나 있을 때마다 소스 0.2리터가 필요해요.

층의 배열을 매개변수로 받는 quantities 함수를 정의해요. 그러면 이 함수는 요리를 만드는 데 필요한 면과 소스의 양을 계산해요. 결과는 noodles와 sauce라는 키를 가진 객체로 반환해야 해요.

quantities(['sauce', 'noodles', 'sauce', 'meat', 'mozzarella', 'noodles']);
// => { noodles: 100, sauce: 0.4 }

4. 비밀 재료 넣기

얼마 전에 친구를 방문해서 그곳에서 라자냐를 먹었어요. 정말 훌륭했고 뭔가 특별한 맛이 났어요. 친구가 재료 목록을 보내 주면서, 목록의 마지막 항목이 그 요리를 그렇게 특별하게 만든 "비밀 재료"라고 알려줬어요. 이제 그 비밀 재료를 자신의 레시피에도 넣고 싶어요.

재료 배열 두 개를 매개변수로 받는 addSecretIngredient 함수를 작성해요. 첫 번째 매개변수는 친구가 보내 준 목록이고, 두 번째는 자신의 레시피 재료 목록이에요. 이 함수는 친구의 목록에서 마지막 항목을 자신의 목록 끝에 추가해야 해요. 자신의 레시피를 나타내는 배열은 직접 수정되어야 하고, 함수는 아무것도 반환하지 않아야 해요. 하지만 첫 번째 인자는 수정되면 안 돼요.

const friendsList = ['noodles', 'sauce', 'mozzarella', 'kampot pepper'];
const myList = ['noodles', 'meat', 'sauce', 'mozzarella'];

addSecretIngredient(friendsList, myList);
// => undefined

console.log(myList);
// => ['noodles', 'meat', 'sauce', 'mozzarella', 'kampot pepper']

5. 레시피의 양 조절하기

요리책에 적힌 양은 두 인분 분량의 라자냐만 만들 수 있어요. 다음에는 더 많은 사람을 위해 요리하고 싶으니, 인분 수에 따른 양을 계산하고 싶어요.

매개변수 두 개를 받는 scaleRecipe 함수를 구현해요.

  • 2인분에 필요한 양을 담고 있는 레시피 객체예요. 객체의 형식은 아래 예제에서 볼 수 있어요.
  • 만들고 싶은 인분 수예요.

이 함수는 원하는 인분 수에 필요한 양을 담은 레시피 객체를 반환해야 해요. 다만 원래 레시피는 그대로 두고 싶어요. 즉, 이 과제에서는 레시피 인자가 수정되면 안 돼요.

const recipe = {
  noodles: 200,
  sauce: 0.5,
  mozzarella: 1,
  meat: 100,
};

scaleRecipe(recipe, 4);
// =>
// {
//   noodles: 400,
//   sauce: 1,
//   mozzarella: 2,
//   meat: 200,
// };

console.log(recipe);
// =>
// {
//   noodles: 200,
//   sauce: 0.5,
//   mozzarella: 1,
//   meat: 100,
// };
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
JavaScript Exercism

라자냐 마스터 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 JavaScript 트랙을 개념 37개연습 문제 159개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.