
4장 내용.
자바스크립트 함수의 특징
- 자바스크립트 함수는 일급 객체(first-class object)로 다루어짐
- 즉 변수에 할당되거나 함수에 파라미터, 반환값으로 사용되는 등, '값'처럼 다룰 수 있음
- 다른 함수를 인수로 받거나 반환하는 함수를 고차 함수라고 함
- 함수에 파라미터로 넘긴 변수는 값이 '복사'됨, 즉 함수 내에서 값이 변경되어도 외부에선 그대로임
- 하지만 객체를 넘겼을 경우 함수 내부에서 객체의 속성값을 변경하면 외부에도 영향을 줌 (엄격 모드 제외)
함수 선언문
- function 키워드를 통해 이름 있는 함수를 정의하는 방식
- 호이스팅이 발생하여 정의하기 전에도 호출할 수 있음
foo();
function foo() {
console.log("Hello, World!");
}
함수 표현식
- 동일하게 function 키워드를 사용하지만 변수에 할당하거나 함수에 파라미터로 전달할 때 쓰는 방법
- 즉, 다른 곳에서 표현식으로서 사용될 수 있음
- 함수 이름을 지정하지 않은 익명 함수를 정의할 수 있음
const hi = function () {
console.log("Hello, World!");
};
화살표 함수
- 함수 표현식을 간결하게 정의할 수 있도록 함
- 이름을 지정할 수 없음
- 호출 시점에 this가 바인딩되지 않음
// 일반 함수
function foo() {
console.log(this);
}
const obj = {foo};
console.log(foo); // Window 객체
console.log(obj); // {foo: f} (= obj 객체)
- 일반 함수는 위의 예시처럼 어디서 foo()를 호출했는지에 따라 foo()의 this가 달라짐
- 하지만 화살표 함수는 어디서 호출했는지랑 상관 없이 무조건 this가 상위 스코프를 가리킴
- 그래서 React의 컴포넌트 안에서 화살표 함수를 사용하면 무조건 컴포넌트를 가리킴
// 화살표 함수
const foo = () => {
console.log(this);
}
const obj = {foo};
console.log(foo); // Window 객체
console.log(obj); // Window 객체
- 함수가 정의된 시점의 this를 그대로 유지하기 때문에 콜백에서 유용 (아래 setTimeout 예제)
- 기본적으로 arguments 객체를 사용할 수 없으며, 쓰려면 직접 정의해야 함.
// 일반 함수
function foo(a, b) {
console.log(arguments);
}
foo(10, 20, 30); // [10, 20, 30]
// 매개변수는 2개만 지정했지만 모든 인수를 가져올 수 있음
// 배열처럼 생겼지만 Array-Like 객체
// .length, arguments(0)은 되지만 forEach(), map() 같은 배열 전용 메서드는 불가
// 화살표 함수
const foo = (...args) => {
console.log(args); // Array-Like가 아닌 진짜 배열
};
- setTimeout에서 화살표 함수를 사용하면 정의된 시점의 this 그대로 유지 가능
// 일반 함수
const obj = {
value: 42,
foo: function () {
setTimeout(function () {
console.log(this.value);
}, 1000);
}
};
obj.foo(); // undefined
// 왜 ?? -> setTimeout은 Window의 객체임
// 그래서 setTimeout 안에서 정의된 익명 함수의 this는 Window를 가리킴
// 해결 방법 1
const obj = {
value: 42,
foo: function () {
const self = this; // 수동 바인딩
setTimeout(function () {
console.log(self.value);
}, 1000);
}
};
// 해결 방법 2
const obj = {
value: 42,
foo: function () {
setTimeout(function () {
console.log(this.value);
}.bind(this), 1000); // 바인딩
}
};
// 화살표 함수
// 자신의 this가 없기 때문에 바깥 this를 씀
// 그래서 콜백에서 화살표 함수를 쓰면 직관적
const obj = {
value: 42,
foo: function () {
setTimeout(() => {
console.log(this.value);
}, 1000);
}
};
obj.foo(); // 42
- 객체 리터럴을 반환할 땐 중괄호만 쓰면 코드 블록으로 인식하기 때문에 겉에 소괄호로 한번 감싸줘야 함
const getName = () => ({name: "doringri"});
console.log(getName());
Function 생성자
- 문자열로 코드 만들어서 실행하는 방식
- 혹시라도 사용자 입력 들어가면 XSS에 취약하기에 잘 안씀
const fn = new Function("a", "b", "return a + b");
fn(1, 2); // 3
배열 메서드
- map 메서드는 배열의 각 요소를 가지고 만든 새로운 배열을 반환하며, 기존 배열 변환하지 않음
- 새로운 배열을 반환하기 위한 목적이 아닌 순회 목적이면 비효율적이므로 forEach나 for...of를 사용하는 게 적절
- filter 메서드는 조건에 맞는 요소만 가지고 새 배열을 반환함
- reduce 메서드는 이전에 처리된 값과 각 요소를 누적 계산하여 최종적으로 하나의 결과를 반환함
// reduce는 합산이나 데이터 그룹핑에 유용
// FP에 유용 (for문 안쓰고 데이터 변환 가능하니까)
// 콜백 첫번째 파라미터(acc): 누적값, 콜백 두번째 파라미터(cur): 현재 값
// 첫번째 인수(callback): 실행할 함수, 두번째 인수(0): 초깃값
const sum = arr.reduce((acc, cur) => acc + cur, 0);
순수 함수
- FP에서 자주 쓰이는 개념
- 함수 외부 상태에 의존하거나 외부 상태를 변경하지 않음
- 동일한 입력이 주어지면 동일한 출력을 반환함
- sort 대신 toSorted 메서드가 도입된 것처럼 자바스크립트는 순수 함수 방향으로 가는 중
const original = [3, 2, 1];
console.log(original.toSorted()); [1, 2, 3];
console.log(original); [3, 2, 1];
비동기 함수
- async 함수를 쓰면 try-catch로 예외처리 가능
- ECMAScript 2022 이후 자바스크립트 모듈(ES Modules) 최상위에서도 await 사용 가능
- React(SPA) 컴포넌트 모듈 최상단에서도 await를 쓸 수 있지만 JS 다운로드 후 실행 중에 브라우저에서 await가 걸리므로 사용자 입장에서는 화면이 멈춰 보임 (그래서 최상단 await 대신 useEffect나 TanStack Query 사용)
- 하지만 Next.js의 RSC는 브라우저로 보내기 전에 서버에서 await가 실행되므로 멈춤 상태로 보이지 않음 (지연시간 동안은 브라우저에서 로딩 스피너가 표시되며, await 끝나기 전까지 Suspense + Streaming으로 일부 먼저 보여줄 수도 있음)
생성자 함수
- new 연산자를 사용해 호출 가능한 함수
- 생성자 함수가 new를 통해 호출되면 빈 객체가 만들어짐
- 빈 객체는 생성자 함수 내부에서 this로 바인딩되며 속성을 추가할 수 있음
- 빈 객체의 프로토타입은 생성자 함수의 prototype 속성에 연결된 객체임
- 생성자 함수가 원시값을 반환하거나 아무것도 반환하지 않으면 this로 바인딩된 객체 반환, 객체를 반환하면 그 객체 반환
- 화살표 함수, async 함수, 메서드는 생성자 함수로 사용할 수 없음
- 생성자 함수는 class 나오기 전까지는 많이 썼음
function Person(name, age) {
this.name = name
this.age = age
return "doringri"; // 무시하고 { name: "철수", age: 20 } 반환
// return { name: "doringri" }; // 이러면 이 객체 반환
}
Person.prototype.toString = function () {
return `${this.name},${this.age}`;
};
const me = new Person("철수", 20)
console.log(me) // { name: "철수", age: 20 }
console.log(me.toString()) // "철수,20"
바인딩된 함수
- this를 함수에 바인딩하는 기능
- this를 쓰고 싶은데 메서드 실행 위치가 다른 곳(아래 예시에서는 setTimeout 내부)이라 this가 깨질 때 주로 사용함
const obj = {
name: "철수",
sayHi() {
console.log(this.name);
}
};
// obj.sayHi 를 부르는 순간 메서드가 obj로부터 분리됨
setTimeout(obj.sayHi, 1000); // undefined 뜨거나 window.name 뜸
setTimeout(obj.sayHi.bind(obj), 1000); // "철수"
- 엄격 모드에서는 this가 undefined이므로 bind 필수적으로 사용
"use strict";
const person = {
name: "doringri",
say() {console.log(`name: ${this.name}`);}
};
person.say(); // 에러
person.say.bind(person)(); // "name: doringri"
// bind()는 새 함수 반환만 하고 실행은 안함
- this뿐 아니라 인수도 바인딩시킬 수 있음
function add(a, b) {
return a + b;
}
const add1 = add.bind(null, 1);
const add7 = add.bind(null, 7);
console.log(add1(9)); // 10
console.log(add7(9)); // 16
예시 코드가 많아서 생각보다 길어졌음,,
'IT > JavaScript & TypeScript' 카테고리의 다른 글
| [JavaScript] DFS 상태 트리 (0) | 2025.11.08 |
|---|---|
| [JavaScript] 가장 먼 노드 (BFS 그래프 알고리즘) (0) | 2025.11.07 |
| [TypeScript] Null, Undefined 체크 (0) | 2025.10.31 |
| [TypeScript] 문자열 key 검증하기 (0) | 2025.10.28 |
| [JavaScript] 타입 (0) | 2025.10.21 |