영화 목록 사이트 제작 개인 프로젝트 하면서 사용하고 있었지만 이해가 제대로 되지 않은 채 사용한 부분이었던 함수를 다시 정리해보려한다.
함수 정의 방식 | 예시 |
---|---|
함수 선언문 | function add(x, y) { return x + y; } |
함수 표현식 | var add = function(x, y) |
fucntion add(x, y) {
return x + y;
}
var add = function(x, y) {
return x+ y;
}
// 함수 참조
console.dir(add); // f add(x, y)
console.dir(sub); // undefined
// 함수 호출
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // Type Error!!
// 함수 선언문
function add(x, y) {
return x + y;
}
// 함수 표현식
var sub = function(x, y) {
return x - y;
}
함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다름
함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있다.
함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.
함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 함수 호이스팅이라 한다.
⚠️ 함수 호이스팅과 변수 호이스팅은 미묘한 차이가 있음
- 변수 할당문의 값은 할당문이 실행되는 시점인 런타임에 평가된다.
-> 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다.
-> 함수 표현식으로 함수를 정의하면 함수 호이스팅이 아닌 변수 호이스팅이 발생한다.
// 익명 실행 함수
(function () {
var a = 3;
var b = 5;
return a * b;
}());
// 기명 실행 함수
(function foo () {
var a = 3;
var b = 5;
return a * b;
}());
function countDown(n) {
if(n < 0) return;
consol.log(n);
countDown(n - 1); // 재귀 호출
}
countDown(10);
function factorial(n) {
// 탈출 조건: n이 1 이하일때 재귀 호출을 멈춘다.
if(n <= 1) return 1;
// 재귀 호출
return n * factorial(n - 1);
}
console.log(factorial(0)); // 0! = 1
console.log(factorial(1)); // 1! = 1
console.log(factorial(2)); // 2! = 2 * 1 = 2
console.log(factorial(3)); // 3! = 3 * 2 * 1 = 6
var factorial = function foo (n) {
// 탈출 조건: n이 1 이하일때 재귀 호출을 멈춘다.
if(n <= 1) return 1;
// 재귀 호출
return n * factorial(n - 1);
// === return n * foo(n - 1);
}
function outer() {
var x = 1;
// 중첩 함수
fucntion inner() {
var y = 2;
// 외부 함수의 변수를 참조할 수 있다.
console.log(x + y);
}
inner();
}
outer();
콜백 함수는 고차 함수에 의해 호출되며 이때 고차함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.
-> 고차 함수에 콜백 함수 전달할 때 콜백 함수를 호출하지 않고 함수 자체를 전달해야 한다.
// 외부에서 전달받은 함수를 n만큼 반복 호출
fucntion repeat(n, f) {
for(var i = 0; i < n; i++) {
f(i); // i 전달하며 f 호출
}
}
var logAll = function (i) {
console.log(i);
};
// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logAll); // 0 1 2 3 4
var logOdds = function (i) {
if(i % 2) console.log(i);
};
// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logOdds); // 1, 3
// 익명 함수 리터럴을 콜백 함수로 고차 함수에 전달한다.
// 익명 함수 리터럴은 repeat 함수를 호출할 때마다 평가되어 함수 객체를 생성한다.
repeat(5, function(i) {
if(i % 2) console.log(i);
});
// logOdds 함수는 단 한 번만 생성된다.
var logOdds = function (i) {
if(i % 2) console.log(i);
};
// 고차 함수에 함수 참조를 전달한다.
repeat(5, logOdds);
document.getElementById('myBtn').addEventListener('click', function() {
console.log('clicked!');
})
// 콜백 함수 사용한 비동기 처리
// 1초 후에 메시지를 출력
setTimeout(function() {
console.log('1초 경과');
}, 1000);
// map
var res = [1, 2, 3].map(function(item) {
return item * 2;
});
console.log(res); // [2, 4, 6]
// filter
res = [1, 2, 3].filter(function(item) {
return item % 2;
});
console.log(res); // [1, 3]
// reduce
res = [1, 2, 3].reduce(function (acc, cur) {
return acc + cur;
}, 0);
console.log(res); // 6
외부 상태: 전역 변수, 서버 데이터 파일, Console, DOM 등
// 현재 카운트
var count = 0;
// 순수 함수는 동일한 인수가 전달되면 언제나 동일한 값 반환
function increase(n) {
return ++n;
}
// 순수 함수가 반환한 결과 값을 변수에 재할당해서 상태를 변경
count increase(count);
console.log(count); // 1
count increase(count);
console.log(count); // 2
var count = 0;
// 비순수 함수
function increase() {
return ++count; // 외부 상태에 의존하며 외부 상태를 변경한다.
}
// 비순수 함수는 외부 상태를 변경, 상태변화 추적하기 어려워짐
increase();
console.log(count); // 1
increase();
console.log(count); // 2
함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해서 불변성을 지향하는 프로그래밍 패러다임이다.
로직 내 존재하는 조건문과 반복문을 제거하여 복잡성 해결, 변수 사용을 억제하거나 생명주기를 최소화해서 상태 변경을 피해 오류를 최소화하는 것을 목표로 한다.
참고자료: 모던 자바스크립트 deep dive - 이웅모 저