JAVASCRIPT DEEP DIVE 2회독 12장 - 함수 part 2

김명성·2022년 5월 20일
0

매개변수의 최대 개수

함수의 매개변수는 코드를 이해하는 데 방해되는 요소이므로 이상적인 매개변수 개수는 0개이며 적을수록 좋다.
매개변수의 개수가 많다는 것은 함수가 여러 가지 일을 한다는 증거이므로 바람직하지 않다.
이상적인 함수는 한가지 일만 해야 하며 가급적 작게 만들어야 한다

ajax.request({
  method: 'POST',
  url: API_URL,
  header:{
  content: 'some',
  apikey: API_KEY,
  username: USER_NAME
  },
  data: {id: 1, name: 'Kim'}
});

객체를 인수로 사용하는 경우 프로퍼터 키만 정확히 지정하면 매개변수의 순서를 신경 쓰지 않아도 된다.
또한 명시적으로 인수의 의미를 설명하는 프로퍼티 키를 사용하게 되어 가독성과 실수가 방지된다.
주의할 것은, 함수 외부에서 함수 내부로 전달한 객체를 함수 내부에서 변경하면 함수 외부의 객체가 변경되는 부수 효과가 발생된다.

반환문

함수는 return 키워드와 표현식(반환값)으로 이뤄진 반환문을 사용해 실행 결과를 함수 외부로 반환할 수 있다.
함수는 return 키워드로 모든 값을 반환할 수 있다.
반환문은 함수의 실행을 중단하고 함수 몸체를 빠져나가는 역할과 return 키워드 뒤에 오는 표현식을 평가해 반환한다.
return 키워드 뒤에 반환값으로 사용할 표현식을 명시적으로 지정하지 않으면 undefined가 반환된다.

반환문은 생략할 수 있으며, 함수의 마지막 문까지 실행 후 암묵적으로 undefined를 반환한다.


참조에 의한 전달과 외부 상태의 변경

매개변수 또한 변수와 동일하게 취급되어 매개변수의 타입에 따라 값에 의한 전달, 참조에 의한 전달 방식을 그대로 따른다.

function changeVal(primitive, obj) {
  primitive += 100;
  obj.name = 'Kim';
}

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

changeVal(num,person);

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

객체는 변경 가능한 값으로 새로운 원시값으로 교체된다.
이 문제를 해결하기 위해 객체를 불변 객체로 만들어 사용할 수 있다.
객체의 복사본을 새롭게 생성하는 것은 비용이 들지만 변경 불가능한 값으로 동작하게 만드는 것이다.
객체의 상태 변경이 필요한 경우 객체의 방어적 복사를 통해 원본 객체를 완전히 복제하는 깊은 복사를 통해 새로운 객체를 생성하고 재할당을 통해 교체한다. 이를 통해 외부 상태가 변경되는 부수 효과를 없앨 수 있다.

외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 함수를 순수 함수라 한다.

재귀함수

자기 자신을 호출하는 재귀 함수를 사용하면 반복되는 처리를 반복문 없이 구현할 수 있다.

// 팩토리얼
// 팩토리얼은 1부터 자신까지의 모든 양의 정수의 곱이다.
function factorial(n){
  if(n <= 1) return 1;
  
  return n * factiroal(n - 1);

재귀호출을 실행할 때에는 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 한다.

중첩함수

함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다.
중첩 함수를 포함하고 있는 함수를 외부 함수라 부른다.
중첩 함수는 외부 함수 내부에서만 호출할 수 있다.
일반적으로 중첩 함수는 자신을 포함하는 외부 함수를 돕는 핼퍼 함수의 역할을 한다.
ES6부터 함수 정의는 문이 위치할 수 있는 문맥이라면 어디든 가능하다.

function outer() {
  var x = 1;
  
  function inner() {
    var y = 2;
    console.log( x + y ); // 3
  }
  
  inner();
}

outer();

콜백 함수

함수의 변하지 않는 공통 로직은 미리 정의해 두고, 경우에 따라 변경되는 로직은 추상화하여 함수 외부에서 함수 내부로 전달하는 것이 콜백함수다.

function repeat(n, callback){
  for (let i = 0; i < n; i++){
    callback(i);
  }
};

const logAll = (i) => {
  console.log(i);
}

const logOdds = (i) => {
  if( i % 2 ) {
    console.log(i);
  }
};

repeat(5, logAll) // 0 1 2 3 4
repeat(5,logOdds) // 1 3

위 repeat 함수는 경우에 따라 변경되는 일을 함수 callback으로 추상화했고 외부에서 전달받는다.
repeat 함수는 더 이상 내부 로직에 강력히 의존하지 않고 외부에서 로직의 일부분을 함수로 전달받아 수행하므로 더욱 유연한 구조를 갖게 되었다.

이처럼 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라 하며, 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 한다.

중첩 함수가 외부 함수를 돕는 헬퍼 함수의 역할을 하는 것처럼 콜백 함수도 고차 함수에 전달되어 핼퍼 함수의 역할을 한다.
중첩 함수는 내부에 고정되어 있어 교체가 곤란하지만 콜백 함수는 함수 외부에서 내부로 주입되기 떄문에 자유롭게 교체할 수 있다는 장점이 있다.
즉, 고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.
고차 함수는 매개변수를 통해 전달받은 콜백 함수의 호출 시점을 결정해서 호출한다.
콜백 함수는 고차함수에 의해 호출되며 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
따라서 고차 함수에 콜백 함수를 전달할 때 콜백 함수를 호출하지 않고 함수 자체를 전달해야 한다.
콜백 함수가 고차 함수 내부에서만 호출된다면 콜백 함수를 익명 함수 리터럴로 정의하면서 곧바로 고차 함수에 전달하는 것이 일반적이다.

콜백 함수는 비동기처리 (이벤트 처리, Ajax 통신, 타이머 함수 등)에 활용되는 중요한 패턴이다.

콜백 함수는 비동기 처리 뿐만 아니라 배열 고차 함수에서도 사용된다.
자바스크립트에서 배열은 사용 빈도가 매우 높은 자료구조이고 배열을 다룰 때 배열 고차 함수는 매우 중요하다.

순수 함수와 비순수 함수.

외부상태에 의존하지 않고 변경하지 않는, side Effect가 없는 함수를 순수 함수라 한다. 그리고 그 정반대는 비순수 함수다.
순수 함수는 외부 상태에 의존하지 않고 오직 매개변수를 통해 함수 내부로 전달된 인수에게만 의존해 값을 생성해 반환한다.
함수의 외부 상태에 의존하는 함수는 외부 상태에 따라 반환값이 달라진다.
외부 상태에는 전역 변수, 서버 데이터, 파일, Console, Dom 등이 있다.
만약 외부 상태에는 의존하지 않고 함수 내부 상태에만 의존한다 해도 그 내부 상태가 호출될 때마다 변화하는 값(ex: current time)이라면 순수 함수가 아니다.
순수 함수는 일반적으로 하나 이상의 인수를 전달받는다.
그리고 순수 함수는 인수를 변경하지 않는 것이 기본이다.
다시 말해 순수 함수는 인수의 불변성을 유지한다.

비순수 함수의 예시

let updateValue;
let updateCurrentIdx;
function changeTodoTitle(e) {
  const {value} = e.target // value == todo.id
  updateValue = value
  updateCurrentIdx = todos.findIndex(todo => todo.id === value)
  onToggleUpdateInput(true)
};

인수를 전달받지 않고 함수 내부에서 외부 상태를 직접 참조하면 외부 상태에 의존하게 되어 반환값이 변할 수 있고 외부 상태에도 변경할 수 있으므로 비순수 함수가 된다.
비순수 함수는 값이 언제든지 변경될 수 있어 오류 발생의 근본적 원인이 될 수 있다.
자바스크립트는 멀티 패러다임 언어이므로 객체지향프로그래밍 뿐만 아니라 함수형 프로그래밍을 적극적으로 활용하고 있다.


자바스크립트는 멀티 패러다임 언어이므로 객체지향프로그래밍 뿐만 아니라 함수형 프로그래밍을 적극적으로 활용하고 있다.

함수는 한가지 일만 해야 하며 가급적 작게 만들어야 한다.
객체를 인수로 사용하는 경우 프로퍼터 키만 정확히 지정하면 매개변수의 순서를 신경 쓰지 않아도 된다.

반환문 return
함수는 return 키워드와 표현식(반환값)으로 이뤄진 반환문을 사용해 실행 결과를 함수 외부로 반환할 수 있다.
함수는 return 키워드로 모든 값을 반환할 수 있다.
반환문은 함수의 실행을 중단하고 함수 몸체를 빠져나가는 역할과 return 키워드 뒤에 오는 표현식을 평가해 반환한다.
return 키워드 뒤에 반환값으로 사용할 표현식을 명시적으로 지정하지 않으면 undefined가 반환된다.
반환문은 생략할 수 있으며, 함수의 마지막 문까지 실행 후 암묵적으로 undefined를 반환한다.

객체의 방어적 복사
객체의 상태 변경이 필요한 경우 객체의 방어적 복사를 통해 원본 객체를 완전히 복제하는 깊은 복사를 통해 새로운 객체를 생성하고 재할당을 통해 교체한다. 이를 통해 외부 상태가 변경되는 부수 효과를 없앨 수 있다.

순수함수
외부 상태를 변경하지 않고 외부 상태에 의존하지도 않는 함수를 순수 함수라 한다.
외부 상태에 의존하지 않고 함수 내부 상태에만 의존한다 해도 그 내부 상태가 호출될 때마다 변화하는 값(ex: current time)이라면 순수 함수가 아니다.
순수 함수는 일반적으로 하나 이상의 인수를 전달받는다.
그리고 순수 함수는 인수를 변경하지 않는 것이 기본이다.
다시 말해 순수 함수는 인수의 불변성을 유지한다.

비순수함수
인수를 전달받지 않고 함수 내부에서 외부 상태를 직접 참조하면 외부 상태에 의존하게 되어 반환값이 변할 수 있고 외부 상태에도 변경할 수 있으므로 비순수 함수가 된다.

중첩함수
함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다.
중첩 함수를 포함하고 있는 함수를 외부 함수라 부른다.
중첩 함수는 외부 함수 내부에서만 호출할 수 있다.
일반적으로 중첩 함수는 자신을 포함하는 외부 함수를 돕는 핼퍼 함수의 역할을 한다.

콜백함수
함수의 변하지 않는 공통 로직은 미리 정의해 두고, 경우에 따라 변경되는 로직은 추상화하여 함수 외부에서 함수 내부로 전달하는 것이 콜백함수다.

콜백함수와 고차함수(HOF)
함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라 하며, 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 한다.
고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.

0개의 댓글