[Javascript]함수(2)

함수 호출과 값




1. 함수 호출

const add = function (x, y) {
  return x + y;
};

add(1, 2); // 함수 호출

위 예시에서 처럼 함수 식별자를 소괄호 쌍과 함께 호출하고, 매개 변수가 있다면 소괄호 안에 인자로 함께 넣어 호출한다.
함수를 호출하면 현재의 스크립트 실행 흐름을 중단하고 호출된 함수로 실행 흐름을 옮긴다.

1) 매개변수와 인수

함수를 실행할 때 필요한 값들을 함수 외부에서 함수 내부로 전달할 필요가 있을 경우, 매개변수를 통해 인수를 전달한다. 또 매개변수에는 갯수와 타입에 제한이 없다. 그외의 특징들을 살펴보자.

// 함수 선언문
function add(x, y) {
  return x + y;
}

// 함수 호출
// 인수 1과 2는 매개변수 x와 y에 순서대로 할당되고 함수 몸체의 문들이 실행된다.
var result = add(1, 2);
function add(x, y) {
  console.log(x, y); // 2 5
  return x + y;
}

add(2, 5);

console.log(x, y); // ReferenceError: x is not defined
function add(x, y) {
  console.log(x, y); // 2 undefined
  return x + y;
}

add(2, 5);
function add(x, y) {
  // Arguments(3) [2, 5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  return x + y;
}

console.log(add(2, 5, 10)); // 7

2) 인수 확인

자바스크립트는 동적 타입 언어다. 따라서 매개변수의 타입을 사전에 지정할 수 없고, 심지어 매개변수와 인수의 갯수가 맞는지조차 체크하지 않는다. 따라서 넘어온 인수가 적절한지 확인할 필요가 있다.

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

console.log(add(2)); // NaN : 갯수가 틀림
console.log(add("a", "b")); // 'ab' : type이 틀림
function add(x, y) {
  if (typeof x !== "number" || typeof y !== "number") {
    // 매개변수를 통해 전달된 인수의 타입이 부적절한 경우 에러를 발생시킨다.
    throw new TypeError("인수는 모두 숫자 값이어야 합니다.");
  }

  return x + y;
}

console.log(add(2)); // TypeError: 인수는 모두 숫자 값이어야 합니다.
console.log(add("a", "b")); // TypeError: 인수는 모두 숫자 값이어야 합니다.

만약에 런타임에 에러 발생이 아닌 사전에 잘못된 호출을 막고 싶다면 자바스크립트의 상위 확장 버전인 타입스크립트를 사용하는 방법이 있다. (사랑해요 타입스크립트)

매개변수와 인수의 갯수가 맞지 않는 문제는 단축 평가 또는 ES6부터 도입된 매개변수의 기본값을 사용하여 undefined를 방지할 수 있다.

//단축 평가
function add(a, b, c) {
  a = a || 0;
  b = b || 0;
  c = c || 0;
  return a + b + c;
}

//기본값 설정
function add(a = 0, b = 0, c = 0) {
  return a + b + c;
}

console.log(add(1, 2, 3)); // 6
console.log(add(1, 2)); // 3
console.log(add(1)); // 1
console.log(add()); // 0

3) 매개변수의 최대 개수

위에서 얘기 했든 매개변수의 개수에는 제한이 없으나, 메모리 문제라던지와 같은 물리적 한계로가 있으므로 자바스크립트 엔진마다 매개변수의 최대 개수의 제한이 사실 있다. 하지만 이 개수의 충분히 많은 숫자이다. 그렇다고 매개변수를 많이 만드는게 과연 좋은 일일까? 매개변수는 순서에 따라 인수를 할당받으므로 가독성, 유지보수, 에러 등을 발생 시킬 요인이 많아지므로 최대한 적게 사용하는 것이 좋다.

매개변수는 0개에 가까울 수록 좋다.

만약 3개 이상 넘어간다면 객체로 만들어서 1개의 인수로 전달하는 것이 좋다.


//Bad
function signUp(name, age, email, password, address, gender){
  ...
}
signUp("홍길동",18,"test@gmail.com","*********","서울시 서초구 방배동", "male");

//Good
function signUp({name, age, email, password, address, gender}){
  ...
}

const userInfo = {
    name:"홍길동",
    age:18,
    email:"test@gmail.com",
    password:"*********",
    address:"서울시 서초구 방배동",
    gender:"male"
  };

signUp(userInfo);

객체를 인수로 넘길 경우, 매개변수의 순서를 신경쓰지 않아도 되고, 인수로 전달할 때 키 값으로 인해 명시적으로 해당 값의 의미를 표현할 수 있다. 다만, 함수 외부에서 함수 내부로 객체를 인수로 전달할 경우, 함수 내부에서 객체의 값을 변경할 경우 함수 외부 객체의 값도 변경된다는 점을 유의하자.

2.반환문

함수는 return키워드와 반환값으로 이뤄진 반환문을 사용해 함수의 실행 결과를 함수 외부로 반환하는 것이다.

function multiply(x, y) {
  return x * y; // 반환문
}

// 함수 호출은 반환값으로 평가된다.
var result = multiply(3, 5);
console.log(result); // 15

반환문은 2가지 역할을 한다.

function multiply(x, y) {
  return x * y; // 반환문
  // 반환문 이후에 다른 문이 존재하면 그 문은 실행되지 않고 무시된다.
  console.log("실행되지 않는다.");
}

console.log(multiply(3, 5)); // 15
function foo() {
  return;
}

console.log(foo()); // undefined
function foo() {}

console.log(foo()); // undefined

반환문은 함수 몸체 내부에서만 사용할 수 있음을 유의한다. 전역에서 사용할 경우 에러가 발생한다. (Node.js는 파일 스코프를 가지므로 에러가 발생하지 않는다.)

Reference

모던 자바스크립트 deep dive
MDN Data_structures