this
자바스크립트에서 this가 가리키는 대상은 함수 호출 방식에 따라 결정된다. 이러한 호출 방식에 의해 결정되는 환경을 실행 문맥(execution context)이라고 하며, this는 그 문맥에 따라 어떤 객체에 바인딩되어 참조 대상이 동적으로 결정된다. 즉, this는 실행되는 시점과 방식에 따라 연결되는 객체(바인딩 대상)가 달라지는 키워드다.
less
this
└── 함수 호출 방식
├── 일반 함수 호출 -> 전역 객체
├── 메서드 호출 -> 메서드를 포함하고 있는 객체
├── 생성자 함수 호출 -> 생성할 객체
└── 콜백 함수 호출 -> 전역 객체 (일반 함수처럼 호출될 경우)전역 컨텍스트(Global Context)
전역 코드에서 this는 실행 환경에 따라 전역 객체를 가리킨다.
js
console.log(this); // 브라우저에서는 window브라우저 환경: window 객체 참조
window는 브라우저의 전역 객체로, 전역 변수나 함수, 타이머 함수(setTimeout 등), 브라우저 API 등을 포함한다.Node.js 환경: global 객체 참조
global은 Node.js의 전역 객체로, 브라우저의 window와 유사하게 전역 변수, 함수, 모듈, 타이머 등을 포함한다.
함수 호출 방식
일반 함수 호출
js
function func() {
console.log(this);
}
func(); // 브라우저에서는 window일반 함수가 호출될 때, 함수 내부의 this는전역 객체(window)를 참조한다.- 이는 호출한 주체가 없기 때문이며, this는 기본적으로 전역 객체에 바인딩된다.
Strict mode에서는 this가undefined가 되며, 암묵적으로 전역 객체에 바인딩되지 않는다.
메서드 호출
js
const cafe = {
brand: "starbucks",
menu: "americano",
print: function () {
console.log(this);
},
};
cafe.print();
// { brand: "starbucks", menu: "americano", print: function () { ... }}- 메서드란, 객체의 프로퍼티로 저장된 함수를 말한다.
- 메서드 내부에서 this는 해당 메서드를 호출한
객체 자신을 가리킨다. - 위 예제에서는
cafe.print()가 호출되었기 때문에, this는 cafe 객체를 참조한다. 즉,this === cafe이다.
js
const cafe = {
brand: "starbucks",
menu: "americano",
newCafe: {
brand: "starbucks",
menu: "latte",
print: function () {
console.log(this);
},
},
};
cafe.newCafe.print();
// { brand: "starbucks", menu: "latte", print: function () { ... }}- print 함수는 newCafe 객체의 메서드로 호출되므로, this는 newCafe 객체를 가리키게 된다.
cafe.newCafe.print()에서 print는 newCafe 객체에 속해 있으므로,this === cafe.newCafe가 된다.
js
const cafe = {
brand: "starbucks",
menu: "americano",
print: function () {
console.log(this);
},
};
const myCafe = cafe.print;
myCafe(); // window- 함수가 객체의 프로퍼티로 존재해도,
호출 방식이 일반 함수라면 this는 해당 객체를 참조하지 않는다. - this는 함수를 어떻게 호출했는지에 따라 결정되는 키워드다. 위 코드에서 print 함수는 cafe 객체의 메서드지만, myCafe에 할당된 뒤
일반 함수로 호출되었기 때문에 this는 전역 객체(window)를 가리킨다. - 함수가 객체의 메서드로 호출되지 않으면, this는 해당 객체를 잃고 전역 컨텍스트에서 동작한다.
생성자 함수 호출
js
function Cafe(menu) {
console.log(this); // new에 의해 만들어진 빈 객체: Cafe { }
this.menu = menu;
}
let myCafe = new Cafe("latte");
console.log(myCafe); // Cafe { menu: "latte" }
// Cafe { }
// Cafe { menu: "latte" }- 생성자 함수는
new키워드와 함께 호출되어새로운 객체(인스턴스)를 생성한다. - 이때 this는
새로 생성 중인 객체를 가리키며, 생성자 함수 내부에서 해당 객체에 프로퍼티를 추가할 수 있다. - 생성자 내부의
this는 빈 객체로 시작해, 프로퍼티를 추가하고 그 객체를 반환하게 된다.
💡 new와 생성자 함수가 함께 작동하는 방식
js
// Cafe 함수 정의
function Cafe(menu) {
console.log(this); // Cafe { }
this.menu = menu;
}생성자 함수로 사용하기 위해 함수 이름은 일반적으로 대문자로 시작하는 관례를 따른다.
js
let myCafe = new Cafe("latte");Cafe 함수를 생성자 함수로 호출하면서, 새로운 객체(Cafe의 인스턴스)를 만들어 myCafe에 할당한다.
내부적으로는:
- 빈 객체가 생성된다:
this = {} - Cafe 함수가 실행되며
this.menu = menu→this.menu = "latte"가 실행된다. - 마지막에 this가 자동으로 반환되어 myCafe에 할당된다.
js
// new 없이 호출
function Cafe(menu) {
console.log(this);
this.menu = menu;
}
let myCafe = Cafe("latte");
console.log(myCafe);
// window
// undefined- new 없이 함수를 호출하면
일반 함수로 실행되며, 내부의 this는 전역 객체(window)를 가리킨다. - 이 경우 Cafe 함수는 객체를 반환하지 않기 때문에(return문이 존재하지 않음) myCafe에는 undefined가 할당된다. 따라서 생성자 함수는 반드시 new와 함께 사용해야 의미가 있다.
콜백 함수 호출
js
const cafe = {
brand: "starbucks",
menu: "",
setMenu: function (menu) {
this.menu = menu;
},
};
function getMenu(menu, callback) {
callback(menu); // 일반 함수처럼 호출
}
getMenu("핫초코", cafe.setMenu);
console.log(cafe);
// { brand: "starbucks", menu: "", setMenu: [Function: setMenu] }- 함수가
콜백 함수로 전달되어 일반 함수처럼 호출되면, 해당 함수의 this는전역 객체(window 또는 global)를 가리킨다. getMenu("핫초코", cafe.setMenu)에서cafe.setMenu는 함수 자체(참조)를 참조 형태로 전달한 것이다. 이때 함수는 cafe 객체의 메서드로 묶인 상태가 아니며, 단순한일반 함수처럼 callback(menu)으로 호출된다.- 그래서, setMenu 내부의 this는 더 이상 cafe를 가리키지 않고, 전역 객체(window 또는 global)를 가리킨다.
- 결국
this.menu = menu;는 cafe 객체의 프로퍼티를 바꾸지 못하고, 전역 객체에 menu를 추가하려고 시도한다.
#오즈코딩스쿨#초격차_프론트엔드_13기#개발기록