JavaScript의 this
는 함수가 어떻게 호출되었는지에 따라 달라집니다.
// 1. 전역 스코프
// 전역 스코프에서 this는 전역 객체를 참조합니다. 브라우저에서는 window 객체가 됩니다.
// (Node 환경에선 global, strict mode에서는 undefined.)
console.log(this === window); // true
// --------------------------------------------
// 2. 함수 호출:
// 일반 함수로서 호출될 때 this는 전역 객체를 참조합니다.
function func() {
console.log(this);
}
func(); // window (브라우저에서)
// --------------------------------------------
// 3. 메서드 호출:
// 객체의 메서드로서 호출될 때 this는 해당 메서드를 호출한 객체를 참조합니다.
const myObj = {
method: function() {
console.log(this);
// this는 myObj를 가르킴.
}
};
myObj.method();
// 3-1.
const myObj = {
outerMethod: {
innerMethod: function(){
console.log(this);
// 이때 this는 outerMethod를 가르키게 됩니다.
}
}
};
// --------------------------------------------
// 4. 생성자 함수:
// new 키워드를 사용하여 생성자 함수를 호출하면, this는 새로 생성된 객체를 참조합니다.
function MyClass() {
this.prop = "value";
}
const instance = new MyClass();
console.log(instance.prop); // "value"
// 4-1.
// 다만, new 생성자 함수 없이 함수를 호출하면, 에러가 발생합니다.
function MyClass() {
this.prop = "value";
}
const instance = MyClass();
console.log(instance.prop); // TypeError: Cannot read properties of undefined
// a) MyClass 함수가 new 생성자 함수 없이 호출되었기에, 해당 함수 내부 this는 전역 window를 가르키게 됩니다.
// b) 또한 MyClass 함수는 리턴 값이 없으므로 instanc는 undefined 입니다.
// 때문에 출력문은 undefined.prop 이 되므로 TypeError를 출력하게 됩니다.
// --------------------------------------------
// 5. 화살표 함수:
// 화살표 함수는 자신만의 this 바인딩을 갖지 않습니다.
// 때문에 상위 함수 scope를 찾아갑니다.
function OuterFunction() {
this.value = "hello";
this.arrowFunction = () => {
console.log(this.value); // "hello"
};
}
const instance = new OuterFunction();
instance.innerFunction();
instance.arrowFunction();
// --------------------------------------------
// 6. call, apply, bind:
// call, apply, bind 메서드를 사용하면 함수를 호출할 때 this의 값을 명시적으로 설정할 수 있습니다.
function showThis() {
console.log(this);
}
const obj1 = { name: "obj1" };
const obj2 = { name: "obj2" };
showThis.call(obj1); // obj1
showThis.apply(obj2); // obj2
const boundFunction = showThis.bind(obj1);
boundFunction(); // obj1
// --------------------------------------------
// 7. 이벤트 핸들러:
// 대부분의 경우, 이벤트 핸들러에서 this는 이벤트를 발생시킨 DOM 요소를 참조합니다.
자주 보이는 예제인데, 헷갈리는 부분이 있었어서 다시 기록하려합니다.
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
// 5, 5, 5, 5, 5
// var를 사용하면 for 루프의 반복마다 새로운 변수 인스턴스가 생성되지 않습니다.
// 따라서 모든 setTimeout 콜백이 루프가 끝난 동일한 i 변수를 참조하게 됩니다.
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
// 0, 1, 2, 3, 4
// 각 setTimeout 콜백들이 for 루프의 각 반복에서의 새로운 i 인스턴스 값을 "캡처"했기에
// 스택 내부의 각 setTimeout들은 서로 다른 i 값을 참조하게 되었습니다.
// 물론 즉시실행함수(IIFE) 또는 forEach문을 사용해도 됩니다.
아직 JS가 많이 부족하구나를 느꼈습니다. 더 꼼꼼히 열심히 공부해야겠어요.