함수형 프로그래밍 언어, JS 함수는 하나의 단위로 실행되는 문들의 묶음이다.
JS에서는 함수도 객체이다. 이런 것들이 함수는 일급 객체다 라는 말이 나온 것 같다. 일급 객체를 정리해보자
📌 일급 객체
일급 시민에서 온 말, 혜택X, 객체든, 함수든 모두 변수 처럼 취급하겠다. -> 사용할 때 다른 요소들과 아무런 차별이 없게 취급하겠다.
- 모든 일급 객체는 변수나 데이터에 담을 수 있어야 한다.
- 모든 일급 객체는 함수의 파라미터로 전달 할 수 있어야 한다.
- 모든 일급 객체는 함수의 리턴값으로 사용할 수 있어야 한다.
다른 언어는 같은 식별자여도 파라미터 갯수에 따라 다른 함수로 인식 되는데, 함수형 프로그래밍을 사용하는 자바스크립트에서는 같게 인식이 된다.
📌 익명 함수
말 그대로 이름이 없다. 함수 선언 시 이름이 없다, 변수에 할당하거나 인자로 전달하는 콜백함수로 사용되곤 한다.
//익명 함수
const sayHi = function(){
console.log("Hi")
}
sayHi()
//일반 함수
function sayHello(){
console.log("Hello")
}
📌 화살표 함수
되게 가볍고 빠르다.
- object method와 같은 non-constructor
- argument가 없으며, 생성자 함수로 호출 안된다.
- 함수를 반환하는 고차 함수에 활용(curring)
//const f3 = () => (x) => {...};
const f3 = y => x => {...};
생략 가능 요소
- function keyword
- 매개 변수가 1개라면 매개변수 괄호
- body가 1개 문이라면 중괄호와 return 문
내부/ 콜백 함수에서는 this가 외부(상위/전역) 객체 이다. -> this와 new를 가질 수 없다.
화살표 함수는 new로 부를 수 없다.
그래서 바인드를 하거나, 직접적으로 버튼의 값을 넣어주면된다. 하지만 this보단 성능이 떨어진다. -> 왜냐면 찾아야돼
📌 즉시 호출 함수(IFFE : Immediately Invoked Function Expression)
가독성이 좋다.
- 불필요한 전역 변수와 메모리 낭비를 줄일 수 있다.
- closure(private) 함수 즉시 반환
- 부분 await 활용 가능
const counter = (function() {
let curr = 0;
return {
inc(n) { curr += n; },
};
})();
📌 함수의 호출 방식과 this
일반함수의 this : global
메소드/생성자 함수 의 this : instance
globalThis.name = "GlobalName";
this.name = "ModuleName";
const obj = {
name: 'ObjName',
bark() { // good!(호출한 객체)
console.log('bark=', this.name);
},
bark2: () => // bad!! (this=전역(browser)/module(node))
console.log('bark2=', this.name), //ModuleName => 모듈화 시켜서 실행하는 걸 알 수 있다.
};
obj.bark(); //ObjName
obj.bark2(); //ModuleName
⭐️ 정리
실행되는 함수의 종류 | 브라우저 | node |
함수 선언문 function(){} |
FunctionDeclaration에 <f.o>로 등록 bind 한 객체 bind하지 않았다면 전역 ([[globalThisValue]]) |
FunctionDeclaration에 <f.o>로 등록 bind 한 객체 bind하지 않았다면 전역 ([[globalThisValue]]) |
화살표 함수 () = > {} |
bind 안 됨! 전역(globalThisValue) 소유자의 Lexical Scope의 this |
bind 안 됨! 모듈 |
객체/instance method | 객체 또는 instance 자신 |
객체 또는 instance 자신 |
method 내 inner funtion 선언문 |
객체 또는 instance 자신 |
global (globalThis) |
함수 선언문 Property f: function() |
FunctionDeclaration에 <f.o>로 등록 소속된 객체 (method) |
FunctionDeclaration에 <f.o>로 등록 소속된 객체 (method) |
화살표 함수 Property 화살표 함수 callback 함수 |
소속된 객체의 부모 bark4: () => { this } Obj의 LexScope this |
소속된 객체의 부모 bark4: () => { this } Obj의 LexScope this |
📌 Timer functions & process.nextTick()
setImmediate() 는 들어가는 속도가 빨라서 딜레이가 없다. setTimeout은 딜레이가 있기 때문에 Eventloop에 차마 못들어가고 다음 Event loop가 올 때 실행이 된다.
‼️ 예제
globalThis.name = 'Global Name';
const obj = {
name: 'Obj Name',
printName() {
console.log(this.name);
},
};
const printName = obj.printName;
printName();
obj.printName 의 함수의 참조를 printName에 할당한 것이다. 그렇기 때문에 할당이 되는 순간 obj와 관련이 없게 된다.
printName()가 힙에 들어가게 되어 실행(호출)을 하게 된다. 힙에 들어간 후에 실행을 한 후의 this니깐 this는 전역을 가르킨다.
그렇기때문에 globalThish.name인 'Global Name' 이 출력이 된다.
this는 함수의 호출 시점에 정해진다. obj.printName() 이라면 obj가 this로 바인딩 된다. 이땐 this.name이 Obj Name이 되게 된다.
const boundPrintName = obj.printName.bind(obj); 으로 사용하면 obj와의 연결을 유지할 수 있다.
답 : Global Name
바인딩, this를 binding하는 방법 : call, apply bind
바인딩한 함수는 원본 함수 객체를 감싸는 함수이다. this가 무엇을 참조하는지 정하는 규칙
✔️ call, apply : 즉시 실행한다.
fn.call(thisBindingObject, args1, args2, …); // call
fn.apply(thisBindingObject, [args1, …]); // apply (array)
바인딩하는 방법이다. y = x.bind(x)() 를 생략하기 위해 나온 방법이다. call과 argument는 arguments만 다르다.
✔️ bind : this를 묶은 새 함수만 리턴, 실행은 하지 않는다.
//bind함수 사용
const dog = {
name: "Maxx",
showMyName() {
console.log(`My name is ${this.name}.`);
},
whatsYourName() {
setTimeout(this.showMyName.bind(dog), 1000);
},
};
//화살표 함수 사용
const dog = {
name: "Maxx",
showMyName() {
console.log(`My name is ${this.name}.`);
},
whatsYourName() {
setTimeout(() => {
this.showMyName();
}, 1000);
},
};
//My name is Maxx
dog.whatsYourName();
화살표함수의 this는 소유자의 this이기 때문에 올바르게 출력이 된다.
Factory Function
어떤 함수가 new 키워드 없이 객체를 반환하는 함수를 말한다.
생성자 함수(Constructor Function)
new 연산자로 불린다. this는 인스턴스 이다. 일반적으로 대문자로 시작한다.
- new는 빈객체를 생성
- 새로 생성된 빈 객체는 생성자의 프로토타입을 상속받음
- this를 새로 생성된 객체에 바인드 시킨다.
- 생성자에 명시적으로 다른 객체를 리턴하지 않는 경우, this로 바인드된 객체가 반환된다.
프로토타입(Prototype)
속성/메서드를 찾는 구조
자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다.
순수 함수
sideEffect가 없는 함수. 동일한 입력값에 동일한 출력값이 나오는 함수를 말한다.
const weeks = ['일', '월', '화', '수', '목', '금', '토'];
const getWeekName = function(weekNo) {
return `${weeks[weekNo]}요일`;
};
const day = new Date().getDay();
console.log(`오늘은 ${getWeekName(day)}입니다!`);
위의 함수가 순수 함수가 아닌 이유는 누군가가 weeks를 의도적으로 바꿀 경우 출력이 달라지게 된다.
const weekName = () => weekNo => {
const weeks = ['일', '월', '화', '수', '목', '금', '토'];
return weeks[weekNo];
};
const day = new Date().getDay();
console.log(`오늘은 ${weekName(day)}요일 입니다!`);
내부에서 정의함으로써, 항상 같은 값을 가지게 할 수 있다.
콜백 함수(Callback Function)
다른 코드의 인수로 넘겨주는 실행 가능한 코드
✔️ debounce
연속적으로 발생한 이벤트를 하나로 처리하는 방식이다.
✔️ throttle
단위 시간당 최소 한번의 이벤트를
고차함수(Higher-Oder Function)
다른 함수를 인자로 받거나, 함수를 반환하는 함수이다.
➡️ 즉 , 함수를 다루는 함수
- 인수로서의 함수
- 반환 값으로서의 함수(closure)
- 식별자로서의 함수(1급 객체)
➡️ 1급 객체로서의 함수
const map = (arr, fn) => {
const result = [];
for (let i = 0; i < arr.length; i++) {
result.push(fn(arr[i]));
}
return result;
};
예시로 map, reduce, filter등이 있다.
unary 함수
고차함수에서 인자를 단 하나만 받는 함수
참고
'JavaScript' 카테고리의 다른 글
[JS] 이터레이터와 제너레이터 (0) | 2025.04.15 |
---|---|
[JS] Debounce 와 Throttle (0) | 2025.04.11 |
[JS] Object&Property (0) | 2025.04.10 |
[JS] 클로저 & 커링 (1) | 2025.04.09 |
[JS] 메모이제이션 (0) | 2025.04.09 |