앞선 포스팅에서도 언급했듯이 JavaScript는 함수 지향 언어이다. 자바스크립트에서는 함수가 1급 시민(First Class Citizen)이므로 함수형 프로그래밍을 지원한다.
그렇다면 1급 시민이란 무엇일까? 이번 포스팅에서는 1급 시민(First Class Citizen)과 1급 객체(First Class Object), 그리고 콜백함수(Callback Function)에 대해 정리하고자 한다.
1급 시민(First Class Citizen)
JavaScript를 포함한 함수형 프로그래밍 언어에서 1급 시민의 조건은 다음과 같다.
- 변수(variable)에 담을 수 있다.
- 다른 함수에 인자(parameter)로 넘길 수 있다.
- 반환값(return value)로 전달할 수 있다.
// 변수에 담을 수 있다.
let bar1 = 1;
// 인자로 전달할 수 있다.
function fn(param) {
console.log(param + 1); //2
}
fn(bar1)
// 반환값으로 전달할 수 있다.
let bar2 = 2;
function fn(param) {
let bar3 = param + 1;
return bar3;
}
console.log(fn(bar2)); // 3
대부분의 프로그래밍 언어에서 숫자는 1급 시민의 조건을 충족한다. 숫자는 변수에 저장할 수 있고, 인자나 반환값으로 전달할 수 있다.
JavaScript에서는 위 조건을 기준으로 봤을 때, 기본 자료형(Number, String, Boolean, Null, Undefined, Symbol, Object(Function, Array))이 1급 시민의 조건을 충족한다.
1급 객체(First Class Object)
1급 객체는 1급 시민(First Class Citizen)의 조건을 충족하는 객체를 말한다. JavaScript에서 객체(Object)는 1급 시민이므로 1급 객체라고 할 수 있다.
// 변수에 담을 수 있다.
let bar1 = { id: '1급 객체' }
// 인자로 전달할 수 있다.
function fn(param) {
let bar2 = param;
bar2.pwd = 'abc123';
// 반환 값으로 전달할 수 있다.
return bar2;
}
console.log(fn(bar1)) // { id: '1급 객체', pwd: 'abc123' }
JavaScript에서 함수는 Prototype을 통해 Object를 상속받아 사용한다. 따라서, JavaScript의 함수 역시 Object이다.
Object이기 때문에 Key 값을 부여하여 사용할 수 있다.
function fn() {}
fn.id = 'first class object';
console.log(fn); // { [Function fn] id: 'first class object' }
결과적으로 JavaScript의 함수는 1급 객체라는 결론을 내릴 수 있다.
1급 함수(First Class Function)
1급 객체 뿐만 아니라 1급 함수도 존재한다. JavaScript에서는 함수를 1급 시민으로 취급한다.
// 변수(variable)에 함수를 담을 수 있다.
let bar1 = function(a, b) {
return a - b;
};
// 함수를 다른 함수에 인자로 넘길 수 있다.
let var2 = function(a, b) {
return a - b;
};
fn(var2);
// 함수에서 함수를 생성하여 반환값(return value)로 전달할 수 있다.
function fn() {
let var3 = function() {
return a + b;
}
return var3;
}
1급 함수는 1급 시민(First Class Citizen)의 조건과 함께 다음과 같은 추가적인 조건이 요구된다.
- 런타임(runtime) 생성이 가능하다.
- 익명(anonymous)으로 생성이 가능하다.
| JavaScript의 함수는 1급 함수? 1급 객체?
JavaScript에서는 객체를 1급 시민으로 취급한다. 그리고 함수도 객체로써 관리되므로 1급 객체라고 할 수 있다. 동시에 JavaScript의 함수는 1급 함수의 추가 조건도 만족한다.
결론적으로 JavaScript의 함수는 1급 객체인 동시에 1급 함수이다.
고차함수(High Order Function)
JavaScript에서 함수가 1급 객체인 것이 중요한 이유가 있다. 그것은 바로 함수가 1급 객체(First Class Object)이므로 고차함수(High Order Function)가 가능하기 때문이다.
고차함수(Higher order function)란 함수를 인자로 전달받거나 함수를 결과로 반환하는 함수를 말한다. JavaScript의 filter, map, sort 등의 함수들이 이에 속한다.
고차함수는 인자로 받은 함수를 필요한 시점에 호출하거나 클로저(Closure)를 생성하여 반환한다. 함수는 생성될 당시의 렉시컬 환경(Lexical Environment)을 기억하게 되는데, 함수를 주고받게 되면 이 렉시컬 환경도 함께 전달된다.
이것을 이용해 커링(currying)과 메모이제이션(memoization)이 가능해진다. 커링과 메모이제이션에 대해서는 추후 따로 포스팅해보도록 하겠다.
콜백함수(Callback Function)
콜백 함수(Callback Function)은 다른 함수에 인자(parameter)로 넘겨주는 함수이다. 다시 말하자면, 파라미터로 함수를 전달 받아서 함수의 내부에서 실행하는 함수이다.
function func(callback) {
callback();
}
앞서 언급했듯이 JavaScript의 함수는 1급 객체(First Calss Object)이다. 따라서 JavaScript의 함수는 마치 변수처럼 사용이 될 수 있다. 콜백 함수는 매개변수를 통해 전달되고, 전달 받은 함수의 내부에서 어느 특정 시점에 실행된다.
콜백함수는 콜백 큐(Callback Queue)에 들어가 있다가 해당 이벤트가 발생하면 이벤트 루프(Event Loop)에 의해 호출된다. 콜백함수는 클로저(Closure)이므로 콜백 큐에 단독으로 존재하다가 호출되어도 콜백함수를 전달받은 함수의 변수에 접근할 수 있다.
콜백함수(Callback Function)의 활용
자바스크립트 엔진은 싱글스레드(Single Thread) 방식이기 때문에 하나의 Call Stack을 갖는다. 그래서 소요되는 시간에 관계없이 한 번에 하나의 작업이 끝나야 다음 작업으로 넘어갈 수 있다.
즉, 동기 처리 방식은 태스크(Task)를 순서대로 하나씩 처리하므로 실행 순서가 보장된다는 장점이 있지만, 앞선 태스크가 종료할 때까지 이후 태스크들이 블로킹(blocking)되는 단점이 있다.
| 그렇다면 콜백함수는 왜 필요할까?
콜백함수는 주로 비동기 처리(Asynchronous Processing)에 사용된다. 비동기(Asyncronous)란 특정 코드의 실행이 끝날 때까지 기다리지 않고 다음 코드로 넘어가는 것을 의미한다.
콜백함수는 비동기 처리를 수행할 수 있도록 해주기 때문에 여러 개의 태스크를 동시에 처리할 수 있다.
setTimeout( )
다음 예시를 보자.
대표적으로 자바스크립트에 내장되어 있는 setTimeout( )이라는 함수가 있다.
const func = () =>{
console.log("waited 3 second"); // 2. waited 3 second (3초 뒤 출력)
}
console.log("Hello"); // 1. Hello
setTimeout(func, 3000);
코드를 실행하면 "Hello"가 먼저 출력된 후, 3초(3000ms)초 뒤에 "waited 3 second"라는 문자열이 콘솔에 출력된다. 어떻게 동작하는 것일까?
- 코드를 실행하면 JavaScript 엔진은 Call Stack에서 "Hello"를 먼저 출력한 후, setTimeout( ) 함수가 실행되어 Call Stack에 setTimeout( ) 함수가 추가된다.
- setTimeout( ) 함수는 자바스크립트 엔진이 처리하지 않고 Web API가 처리한다. setTimeout( ) 함수는 요청한 시간이 지나면 Web API의 Timeout 작업을 인자로 받은 callback 함수를 Task Queue로 전달한다.
- Event Loop는 Call Stack이 비어있는지 항상 확인하는데, console.log("Hello"); 가 살행된 후, Call Stack이 비워진 것을 확인한다.
- Call Stack이 비워진 것을 확인한 Event Loop는 Task Queue에 있던 callback 함수를 Call Stack으로 옮겨 작업을 수행하게 되므로 콘솔에는 "waited 3 second"라는 문자열이 출력된다.
이벤트 핸들러 처리
콜백함수는 이벤트를 처리하기 위해 사용되기도 한다.
<!DOCTYPE html>
<html>
<body>
<button id="myButton">Click</button>
<script>
let button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log('button clicked!');
});
</script>
</body>
</html>
사용자가 버튼을 클릭했을 때 콘솔에는 "button clicked"라는 문자열이 출력된다. button에 addEventListener 메소드를 사용하여 이벤트 리스너를 추가한다. 이벤트 리스너 함수는 두 개의 인자(parameter)를 필요로 한다.
첫번째 파라미터는 이벤트의 타입인 "click"이고, 두번째 파라미터는 버튼이 클릭되었을 때 문자열을 콘솔에 출력하는 콜백함수이다.
콜백 지옥(Callback Hell)
비동기 제어를 위해 콜백함수를 사용하다 보면 함수 안에 함수, 또 그 함수 안에 함수... 와 같이 가독성이 떨어지는 굉장히 복잡한 구조의 콜백 지옥에 빠지는 상황이 발생할 수 있다.
이러한 콜백함수의 단점을 보완하고자 JavaScript는 ES6부터 Promise를 도입했다. Promise에 대해서는 조만간 포스팅해보도록 하겠다.
[참고자료]
[JavaScript] 1급 시민, 1급 객체
JavaScript의 함수는 1급 객체(First Class Object)이다. 1급 객체가 무엇이고 이것이 왜 JavaScript에서 중요할까? 1급 시민(First Class Citizen) JavaScript를 포함한 거의 모든 프로그래밍 언어의 변수에서 1급 시
bbbyung2.tistory.com
자바스크립의 콜백 함수 – 자바스크립트에서 콜백 함수가 무엇이고 어떻게 사용하는지 알아
여러분이 프로그래밍과 익숙하시다면, 함수가 무엇이고 어떻게 사용하는지 알고 계실 겁니다. 그러나 콜백 함수가 뭔지 정확히 알고 있나요? 콜백 함수는 자바스크립트에서 중요한 파트 중 하
www.freecodecamp.org
자바스크립트는 왜 싱글 스레드를 선택했을까? 프로세스, 스레드, 비동기, 동기, 자바스크립트
목차 프로세스와 스레드 프로세스 싱글 스레드와 멀티 스레드 자바스크립트는 왜 싱글 스레드를 선택했을까 동기 vs 비동기 동기 비동기 자바스크립트로 비동기 처리하는 방법 자바스크립트 엔
miracleground.tistory.com
비동기 프로그래밍이란?
비동기란 앞에서 행하여진 사상(事象)이나 연산이 완료되었다는 신호를 받고 비로소 특정한 사상이나 연산이 시작되는 방식. 네이버 국어사전즉, 비동기 프로그래밍이란 특정 코드의 처리가 완
velog.io
'Front-End > JavaScript' 카테고리의 다른 글
[JavaScript] Closure(클로저) (1) | 2023.09.05 |
---|---|
[JavaScript] var, let, const 에 대해 알아보자 (0) | 2023.09.01 |
[JavaScript] Execute Context(실행 컨텍스트) (0) | 2023.08.31 |