📙 (JAVASCRIPT)

자바스크립트 ) 함수의 호출 / 참조에 의한 전달과 외부 상태 변경

놀러와요 버그의 숲 2021. 12. 14. 08:24
728x90
반응형

12.5 함수의 호출 (p.168~174)

 

12.5.1 매개변수와 인수

 

#함수를 호출하는 법

 

함수는 함수를 가리키는 식별자와 한쌍의 소괄호인 함수 호출 연산자로 호출한다.

 

함수 호출 연산자 내에는 0개 이상의 인수를 쉼표로 구분해서 나열한다.

 

매개변수에 인수가 순서대로 할당되고, 함수 몸체의 문들이 실행되기 시작한다.

 

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

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

 

-함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않는다.

 

함수를 호출할 때 매개변수의 개수만큼 인수를 전달하는 것이 일반적이지만, 그렇지 않은 경우에도 에러가 발생하지 않는다.

 

인수가 부족해서 인수가 할당되지 않은 매개변수의 값은 undefined이다

 

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

console.log(add(2)); // 2 + undefined => NaN

 

매개변수보다 인수가 더 많은 경우 초과된 인수는 무시된다.

 

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

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

 

초과된 인수는 그냥 버려지는게 아니라, arguments 객체의 프로퍼티로 보관된다.

 

function add(x, y) {
  console.log(arguments);
  // Arguments(3) [2, 5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]

  return x + y;
}

add(2, 5, 10);

(나는 여기서 arguments를 마치 addEventListener의 event 같이 그냥 주어지는 것이라고 생각했다)

 

cf) argument 객체는 함수 호출 시 전달된 인수들의 정보를 담고 있는 순회 가능한 유사 배열 객체이며, 함수 내부에서 지역 변수처럼 사용된다.

 

 

12.5.2 인수확인

 

 

#함수안에서 적절한 인수가 전달되었는지 확인하는 방법들

 

함수를 정의할 때 적절한 인수가 전달 되었는지 확인할 필요가 있다.

 

왜냐하면 자바스크립트 함수는 매개변수와 인수의 개수가 일치하는지 확인하지 않는다. 

 

 

1. 함수 안에서 조건 만족하지 않을 시 에러 던지기

 

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: 인수는 모두 숫자 값이어야 합니다.

 

 

2.  단축평가 이용

 

function add(a, b, c) {
  a = a || 0;
  b = b || 0;
  c = 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. ES6에 도입된 매개변수 기본 값 사용

 

(매개 변수의 기본값은 매개변수에 인수를 전달하지 않았을 경우와 undeined를 전달한 경우만 유효)

 

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

 

cf) 모던JS 튜토리얼 예제 - 숫자가아니라, 기본값을 문자로 할당하는 경우

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

showMessage("Ann"); // Ann : no text given

 

12.5.3 매개변수의 최대 개수

 

 

매개변수의 개수가 많다는 것은 함수가 여러가지 일을 한다는 증거이므로 바람직하지 않다.

 

따라서 매개변수는 최대 3개 이상을 넘지 않는 것을 권장한다.

 

 

 

12.5.4 반환문

 

*반환문의 역할

 

1. 함수를 실행을 중단하고 함수 몸체를 빠져나간다.

 

2. return 키워드 뒤에 오는 표현식을 평가해 반환한다.

 

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

console.log(multiply(3, 5)); // 15

 

 

만약 return 뒤에 반환값으로 사용할 표현식을 명시적으로 지정하지 않는다면??

 

-return만 썻을경우

function foo () {
  return;
}

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

 

-return조차 쓰지 않았을 경우

function foo () {
  // 반환문을 생략하면 암묵적으로 undefined가 반환된다.
}

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

 

 

그렇다면 반환문은 전역에서도 사용 가능할까??

 

<!DOCTYPE html>
<html>
<body>
  <script>
    return; // SyntaxError: Illegal return statement
  </script>
</body>
</html>

 

 

12.6. 참조에 의한 전달과 외부 상태의 변경(p.175~p.177)

 

원시값은 값에 의한 전달, 객체는 참조에 의한 전달 방식으로 동작한다.

매개변수도 함수 몸체 내부에서 변수와 동일하게 취급되므로,

매개변수 또한 타입에 따라 값에 의한 전달 , 참조에 의한 전달 방식을 그대로 따른다.

 

// 매개변수 primitive는 원시값을 전달받고, 매개변수 obj는 객체를 전달받는다.
function changeVal(primitive, obj) {
  primitive += 100;
  obj.name = 'Kim';
}

// 외부 상태
var num = 100;
var person = { name: 'Lee' };

console.log(num); // 100
console.log(person); // {name: "Lee"}

// 원시값은 값 자체가 복사되어 전달되고 객체는 참조값이 복사되어 전달된다.
changeVal(num, person);

// 원시값은 원본이 훼손되지 않는다.
console.log(num); // 100

// 객체는 원본이 훼손된다.
console.log(person); // {name: "Kim"}

이러한 원인은 원시타입 인수는 값 자체가 복사되어 매개변수에 전달되고,

 

객체 타입 인수는 참조 값이 복사되어 매개변수에 전달되기 때문에, 참조 값을 통해 객체를 변경할 경우 원본이 훼손된다. 

 

 

 

그럼 이렇게 원본이 훼손되는 것을 어떻게 막을까?

 

1.객체를 불변 객체(immutable object)로 만든다. -> 원시 값처럼 변경 불가능한 값으로 만든다.

2. 순수 함수의 이용 -> 외부 상태 변경하지 않기 위해