티스토리 뷰

Running JS 요약

JS - 함수와 추상적 사고

지우개. 2021. 1. 21. 16:44

함수를 바라보는 측면

서브루틴이란 반복되는 작업의 일부를 떼어내서 이름을 붙이고, 언제든지 이름을 불러 중복되는 코드를 없애며 간단하게 만드는 수단입니다. 함수는 이전부터 서브루틴으로서의 용도로 사용되어 왔습니다.

 

기존 서브루틴은 편리하지만 결과값을 다른곳에 활용할 수 없습니다. 이를 해결하기 위해 좀 더 나아가 값을 반환하는 서브루틴을 생각해볼 수 있습니다. 함수는 반환값을 만듦으로서 간단하게 값을 반환하는 서브루틴으로서의 역할을 수행할 수 있습니다.

 

이런 부수적인 측면 뿐만 아니라 당연하게도 함수는 함수 그 자체로서 생각해볼 수도 있습니다. 수학적인 정의의 함수와 마찬가지로 입력이 들어가면 결과가 나오는 함수 말입니다. 이렇게 수학적 정의에 충실한 함수를 순수한 함수라고 부릅니다. 

순수한 함수가 되기 위해서는 입력이 같으면 결과도 반드시 같아야 합니다. 언제, 어디서, 어떻게 호출하느냐에 따라서 결과가 달라서는 안됩니다. 두번째로 순수한 함수는 부수효과가 없어야 합니다. 즉 함수가 호출된다고 해서 프로그램의 상태가 바뀌어서는 안됩니다.

 

const colors = ['red', 'orange', 'yellow', 'green', 'blue'];
let colorIndex = -1;

function getNextRainbowColor() {
	if(++colorIndex >= colors.length) {
    	colorIndex = 0;
    }
    return colors[colorIndex];
}

함수를 호출할 때마다 색상을 반환하는 이 함수는 호출할 때마다 결과가 다르고 함수 외부의 colorIndex 값을 바꾸는 부수효과도 있습니다.

 

이 함수를 순수한 함수로 만들기 위해선 먼저 외부변수값이 달라지는 부수효과를 제거하기 위해 클로저로 감쌉니다.

const getNextRainbowColor = (function() {
	const colors = ['red', 'orange', 'yellow', 'green', 'blue'];
	let colorIndex = -1;
    
    return function() {
	if(++colorIndex >= colors.length) {
    	colorIndex = 0;
    }
    return colors[colorIndex];
    };
})();

 

다음으로 언제나 동일한 인풋-아웃풋의 결과를 주기 위해 이터레이터를 사용합니다.

function getNextRainbowColor() {
	const colors = ['red', 'orange', 'yellow', 'green', 'blue'];
	let colorIndex = -1;
    
    return {
    next() {
      if(++colorIndex >= colors.length) {
          colorIndex = 0;
      }
      return {colors[colorIndex], done: false};
    };
}

 

순수한 함수를 만듦으로서 그렇지 않은 함수가 내재하고 있는 부수효과가 일으킬 숨겨진 버그나 상황에 따라 예상치 못한 값을 내뱉는 위험성을 배재할 수 있기 때문에 함수를 만들 때 순수한 함수를 만드는 습관을 들이길 권장합니다.

 

IIFE와 비동기적 코드

5초에서 시작하고 카운트다운이 끝나면 "go"를 표시하는 프로그램을 만든다고 칩시다.

var i;
for(i=5; i>=0; i--) {
	setTimeout(function(){
	console.log(i===0 ? "go" : i);
    }, (5-i)*1000);
}

Swift나 Java 같은 다른 언어로 작성했다면 예상한 결과가 나왔겠지만, 이 코드는 -1만 여섯 번 출력합니다. setTimeout에 전달된 함수가 루프 안에서 실행되지 않고 루프가 종료된 뒤에 실행되었기 때문입니다. (이해가 잘 되지 않는다면 스코프 개념을 다시 학습할 필요가 있습니다.)

 

let이 등장하기 전 이런 문제를 해결하기 위해 함수를 하나 더 작성해 새로운 스코프를 만들어 매개변수로 값을 캡쳐하는 방법으로 해결하곤 했습니다.

function loopBody(i) {
	setTimout(function() {
    	console.log(i===0 ? "go!" : i);
    }, (5-i)*1000);
}
var i;
for(i=5; i >= 0; i--){
	loopBody(i);
}

ES6 이후에는 익명함수, 즉 IIFE나 let을 사용하여 이 문제를 해결합니다.

'Running JS 요약' 카테고리의 다른 글

JS - 비동기적 프로그래밍  (0) 2021.01.31
JS - 이터레이터와 제너레이터  (0) 2021.01.20
JS - 맵과 셋 / 예외와 에러 처리  (0) 2021.01.18
JS - 객체와 객체지향 프로그래밍  (0) 2021.01.11
JS - 배열  (0) 2021.01.06
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함