일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 리액트
- 렛츠기릿 자바스크립트
- 자바스크립트
- 손에 익히며 배우는 네트워크 첫걸음
- 정재남
- 4주 프로젝트
- codestates
- js
- 코드스테이츠
- 타입스크립트
- javascript
- python
- HTTP
- 타임어택
- 프로그래머스
- 회고
- 제로초
- SQL 고득점 Kit
- LeetCode
- 파이썬
- 백준
- 코어 자바스크립트
- 2주 프로젝트
- programmers
- 타입스크립트 올인원
- 리트코드
- 알고리즘
- 리덕스
- til
- 토익
- Today
- Total
Jerry
#9. this 용법 본문
this는 실행 컨텍스트(Excution Context)에 따라 달라지는 값
즉, 함수 호출 방법에 따라 달라짐
this의 결정 방식 (4가지 규칙 + 1)
1. 기본 호출 규칙 (전역 / 일반 함수 호출)
2. 객체 메서드 호출
3. 생성자 함수 호출 (new 키워드)
4. 명시적 바인드 (call, apply, bind)
5. (추가) 화살표 함수 (Lexical this)
Lexical이란
"어휘적인", "코드가 작성된 위치에 따라 결정되는" 이라는 뜻
즉, Lexical this는 this가 코드가 작성된 위치(상위 스코프)에 의해 결정된다는 의미
1. 기본 호출 규칙 (전역 / 일반 함수 호출)
- this가 window or undefined
- 일반 함수에서 this를 호출하면 전역 객체(window or globalThis)를 가리킴
- 단, strict mode에서는 undefined가 됨
function showThis() {
console.log(this); // 브라우저: window, Node.js: global
}
showThis();
엄격 모드 (strict mode)
"use strict";
function showThis() {
console.log(this); // undefined
}
showThis();
- 객체 내부 함수라도 this는 객체를 가리키지 않음
- 그냥 일반 함수처럼 호출되었기 때문!
const user = {
name: "Alice",
greet() {
function inner() {
console.log(this); // undefined (strict mode) or window (non-strict)
}
inner();
}
};
user.greet();
2. 객체 메서드에서 this
- 위 경우에 this는 해당 객체를 참조
const user = {
name: "Alice",
greet() {
console.log(`Hello, ${this.name}`);
}
};
user.greet(); // Hello, Alice
- 객체에서 this를 변수에 할당하면 this가 깨질 수 있음
const user = {
name: "Alice",
greet() {
console.log(this.name);
}
};
const greetFn = user.greet;
greetFn(); // undefined (일반 함수처럼 호출되면서 this가 window/global을 참조)
=> 그럴 경우, bind 사용
const boundGreet = user.greet.bind(user);
boundGreet(); // Hello, Alice
3. 생성자 함수에서 this (new 키워드)
- 위 경우에서 this는 새로 생성된 객체를 가리킴
function Person(name) {
this.name = name;
}
const john = new Person("John");
console.log(john.name); // John
만약, new 키워드가 없이 호출하면 this는 window(or global0를 가리킴
const p = Person("No New");
console.log(window.name); // "No New" (전역 객체에 name이 설정됨)
=> 그럴 경우, new.target 사용
function Person(name) {
if (!new.target) return new Person(name);
this.name = name;
}
const john = Person("John"); // 자동으로 new를 추가
console.log(john.name); // John
4. 명시적 바인딩
- call, apply, bind를 이용해 this를 강제로 특정 객체에 바인딩 할 수 있음
1) call()
function sayHello() {
console.log(`Hello, ${this.name}`);
}
const user = { name: "Alice" };
sayHello.call(user); // Hello, Alice
2) apply()
- call()과 거의 같지만, 인수를 배열로 전달할 수 있음
function introduce(age, job) {
console.log(`I'm ${this.name}, ${age} years old, working as ${job}.`);
}
const user = { name: "Bob" };
introduce.apply(user, [25, "developer"]);
// I'm Bob, 25 years old, working as developer.
3) bind()
- this를 영구적으로 바인딩하여 새로운 함수 반환
const boundFn = sayHello.bind(user);
boundFn(); // Hello, Alice
- bind() 는 이벤트 핸들러에서도 많이 쓰임
const button = document.querySelector("button");
button.addEventListener("click", user.greet.bind(user));
5. 화살표 함수의 this (Lexical this)
- 위 함수는 this를 상위 컨텍스트에서 가져옴
- 자기 자신이 아닌, 부모 컨텍스트에서 찾음
- 즉, 화살표 함수 내부에서 this를 사용하면, 그 함수를 포함하는 함수(부모)의 this를 따라간다는 뜻
const obj = {
name: "Alice",
greet: () => {
console.log(`Hello, ${this.name}`);
}
};
obj.greet(); // Hello, undefined
// 여기서 this는 obj를 가리키지 않음
// 화살표 함수는 this를 부모 스코프에서 찾음
// greet의 부모는 전역 객체이므로, name이 없음!!!
=> 아래와 같이, this가 greet 메서드의 this를 그대로 가져와서 정상 동작할 수 있음
const obj = {
name: "Alice",
greet() {
const arrowFn = () => console.log(`Hello, ${this.name}`);
arrowFn();
}
};
obj.greet(); // Hello, Alice
내가 혼동되었던 부분
위 화살표 함수의 this 예시에서
"this 키워드는 obj를 가리키고 있지 않다", "화살표 함수는 this를 부모 스코프에서 찾음"
???? 부모 스코프가 obj 아닌가? 왜 부모가 전역 객체지?
먼저, 위 화살표 함수 예시를 기준으로 obj가 부모(샹위 스코프)라는 말이 틀린 건 아니다
- 하지만, this는 스코프(변수 범위)와 다르게 결정된다
"스코프"와 "this 결정 방식"의 차이를 알아보자!!!
(1) 스코프(scope)란?
- "변수를 어디서 찾을 수 있는가?" 결정하는 규칙
- 어떤 함수가 변수나 값을 어디서 찾는지 결정하는 것
> greet, greetArrow 둘 다 obj 안에서 선언되었으므로 obj의 스코프를 가짐const obj = { name: "Alice", greet: function () { console.log(this.name); }, greetArrow: () => { console.log(this.name); } };
> 즉, 둘 다 obj 내부에서 변수 name 찾으려 함
(2) 일반 함수와 화살표 함수에서 this 차이
★ this는 스코프 규칙과 다르게 결정됨!★
- this는 앞에서 보았듯이, * 실행 컨텍스트에 따라 결정됨
- 변수 찾을 때처럼 "스코프 체인"을 따라 올라가지 않음
- 함수를 어떻게 호출했느냐에 따라 결정됨
// 1번 function obj.greet(); // Alice // 2번 arrow function obj.greetArrow(); // undefined ❌
> 1번, greet()는 obj.greet() 형태로 호출 -> this는 obj를 가리킴
> 2번, 화살표 함수는 일반 함수와 다르게 동작 - this는 "함수 선언된 위치"에서 상위 스코프 this를 따라감.
- this가 스코프 체인을 따라가는 게 아니라, 선언된 위치의 this를 그대로 사용!
greetArrow의 this가 결정되는 과정
1. greetArrow는 obj 내부에서 선언됨.
2. 하지만, 화살표 함수는 자기 자신이 this를 결정하지 않고, 선언된 위치의 this를 가져옴.
3. obj 내부에서 선언되었지만, obj 자체가 this를 결정하지 않음!
4. obj가 어디에서 선언되었냐? → 전역 스코프!
5. 전역 스코프에서 this는 window(브라우저 환경) 또는 globalThis(Node.js)
즉, this는 전역 객체(window/globalThis)가 되어 this.name은 undefined가 됨!
실행 컨텍스트
- JS 엔진이 코드 실행 시, 실행 컨텍스트 생성하여 코드 실행에 필요한 정보 저장하고 관리
실행 컨텍스트는 다음을 결정
1. 변수를 어디서 찾을지 (스코프, Lexical 환경)
2. this가 무얼 가리키는지
3. 함수 호출 시 새로운 실행 컨텍스트 생성 및 관리
종류
전역 실행 컨텍스트
- JS 코드 실행되면 가장 먼저 실행
- 브라우저 : window, nodejs : globalThis
함수 실행 컨텍스트
- 함수 호출 시마다, 새로운 실행 컨텍스트 생성
- 함수 실행 종료 시, 해당 컨텍스트는 스택에서 제거
Eval 실행 컨텍스트
- eval() 함수 실행될 때 생성
구조
1. 변수 환경
- var로 선언된 변수와 function 선언 저장
- 외부 환경과의 연결
2. 렉시컬 환경
- let, const 선언된 변수와 function 선언 저장
- 현 실행 컨텍스트의 스코프 체인 관리
- 화살표 함수 this 결정하는 데 사용
3. this 바인딩
- 현 실행 컨텍스트에서 this가 무얼 가리키는지 저장
생성 과정
function hello() { var name = "Alice"; console.log(name); } hello();
1) 전역 실행 컨텍스트 생성
- hello 함수가 메모리에 로드됨. this는 window 또는 globalThis를 가리킴.
2) hello() 함수 실행 → 함수 실행 컨텍스트 생성
- hello 함수 실행 시 새로운 실행 컨텍스트가 생성됨
- name 변수와 console.log(name) 실행
3) hello() 함수 실행 종료 → 함수 실행 컨텍스트 제거
- 함수가 끝나면 해당 실행 컨텍스트가 스택에서 제거됨
실행 컨텍스트는 콜 스택(Call Stack)과 함께 작동
콜 스택은 실행 중인 함수들을 추적하는 스택 구조
function first() { console.log("First"); second(); } function second() { console.log("Second"); third(); } function third() { console.log("Third"); } first();
first() 실행
→ first() 실행 컨텍스트 생성
second() 호출
→ second() 실행 컨텍스트 생성
third() 호출
→ third() 실행 컨텍스트 생성
third() 실행 종료
→ 실행 컨텍스트 제거
second() 실행 종료
→ 실행 컨텍스트 제거
first() 실행 종료
→ 실행 컨텍스트 제거
전역 실행 컨텍스트 → 함수 실행 컨텍스트 → 콜 스택으로 관리
사용 방식 | this가 가리키는 대상 |
전역에서 (strict X) | window 또는 globalThis |
전역에서 (strict O) | undefined |
객체 메서드 호출 | 해당 객체 |
생성자 함수 (new) | 새로 생성된 객체 |
call, apply, bind | 명시적으로 지정한 객체 |
화살표 함수 | 상위 스코프의 this |
6. 실전 활용 예제
this를 활용한 이벤트 핸들러
const button = document.querySelector("button");
const user = {
name: "Alice",
handleClick() {
console.log(`Hello, ${this.name}`);
}
};
// button.addEventListener("click", user.handleClick); ❌ this가 button을 가리킴
button.addEventListener("click", user.handleClick.bind(user)); // ✅ 정상 작동
this를 활용한 클래스
class Counter {
constructor() {
this.count = 0;
}
increase = () => {
this.count++;
console.log(this.count);
};
}
const counter = new Counter();
document.querySelector("button").addEventListener("click", counter.increase);
정리
this는 함수 호출 방식에 따라 결정됨
call, apply, bind로 명시적 지정 가능
화살표 함수는 부모 컨텍스트의 this를 사용
이벤트 핸들러에서는 bind() 활용해 문제 해결 가능
'CS > Terminology' 카테고리의 다른 글
#10. LocalStorage vs SessionStorage vs Cookie (0) | 2025.03.13 |
---|---|
#8. SSR vs CSR (0) | 2025.03.10 |
#7. 호이스팅, 전역 컨텍스트, 클로저 (2) | 2025.03.06 |
#6. REST API vs GraphQL (0) | 2025.03.05 |
#4. REST API란? (0) | 2025.02.25 |