JS ) this에 관하여

devHyuck·2023년 11월 8일

Java Script

목록 보기
1/4
post-thumbnail

제가 공부한 내용을 나름의 해석을 곁들여 서술하였습니다.
완벽한 내용이 아니니 오류가 있을 수 도 있습니다.
틀린 사항에 대한 지적은 환영입니다. 🙂

자바스크립트의 this는 현재 실행 중인 함수메서드에서 참조하는 객체를 가리킵니다.
this의 값은 실행 컨텍스트에 따라 달라질 수 있으며 간단히 분류하면 다음 5가지 정도로 나눌 수 있어요.

  1. 전역 컨텍스트
  2. 메소드
  3. 화살표 함수
  4. 이벤트 리스너
  5. 컨스트럭터

여기서 화살표 함수(arrow function)와 객체 생성자(constructor)를 제외하면 this는 자신의 출생지 혹은 거주지 정도로 생각하면 이해하기 쉬울 것 같네요.

전역 컨텍스트의 this

const 변수 = this;

function 함수(){
 return this;
};

const 변수2 = 함수();

console.log(변수); // window
console.log(변수2); // window

전역 컨텍스트에서 this는 항상 전역 객체를 가리킵니다.
웹 브라우저상의 전역객체는 window이고 일반 함수this 또한 항상 전역 객체를 가리키도록 자바스크립트 초기 버전부터 정의되었죠.

메소드의 this

const 객체 = {
	name: 'kim',
	함수: function () {
		console.log(this);
		console.log(this.name);
	}
};

객체.함수();

// {name: 'kim', 함수: f}
// 'kim'

메소드 호출시에 메소드this는 해당 메소드를 호출한 객체를 가리킵니다.
객체 의 메소드인 함수this값은 객체 가 되는 것이고 두번째 결과값은 객체 의 name인 'kim'이 나오게 됩니다.

그러면 이 경우에는 어떻게 될까요?

const 객체 = {
	name: 'kim',
	함수: function () {
		const 내부함수 = function () {
			console.log(this.name);
		}
		내부함수();
	}
};

객체.함수();

결과값은 undefined.

앞서 일반 함수this값은 전역 객체를 가리키도록 정의되었다고 설명했습니다.
그래서 이런 결과가 나오게 되는데 동작순서를 살펴보면 더욱 이해가 쉬워요.

동작순서는 다음과 같습니다.

  1. 객체의 메소드인 함수를 호출
  2. 함수가 내부함수를 실행
  3. 내부함수는 일반함수이므로 this가 전역객체
  4. window에는 name이 없으므로 결과는 undefine

화살표 함수의 this

자바스크립트는 function 키워드를 사용해 함수를 선언하는데 ES6 버전부터 새로운 함수 선언 키워드를 도입했죠.

const 함수 = () => {}

const 함수 = a => console.log(a)
// function 키워드 대신 화살표를 사용하여 함수선언
// 파라미터가 1개라면 소괄호를 생략가능
// 코드가 한 줄이면 중괄호와 return을 생략가능

이러한 특징들 덕분에 코드를 좀 더 직관적으로 이해 할 수 있습니다.

const 함수 = () => console.log(this);

함수(); // window

화살표 함수this가 없으며 상위 객체this를 상속받아요.

그래서 이렇게 활용가능합니다.

const 객체 = {
	name: 'kim',
	함수: function () {
		const 내부함수 = () => {
			console.log(this.name);
		}
		내부함수();
	}
};

객체.함수();

내부함수화살표 함수로 바꾸면서 내부함수this상위 객체함수 를 참조하여 this값이 객체 가 되어 정상적으로 'kim'이 출력되죠.

이벤트 리스너의 this

<button id="버튼">눌러보세요</button>

document.getElementById('버튼').addEventListener('click', function () {
	console.log(this.innerHTML)
})

이벤트 리스너this는 해당 이벤트가 달린 요소, 즉 e.currentTarget과 같아요.
button 요소 를 클릭한다면 해당 이벤트가 달려있는 요소의 innerHTML눌러보세요 가 콘솔창에 출력됩니다.

이 경우에는 어떻게 될까요?

<button id="버튼">눌러보세요</button>

document.getElementById('버튼').addEventListener('click', function () {
	setTimeout(function(){
		console.log(this.innerHTML)
	},1000)
})

button 요소 를 클릭하면 1초 뒤에 this.innerHTML 이 콘솔에 출력되는 코드입니다.
결과는 undefined가 나오죠.

이해하기 쉽게 설명하자면 이벤트리스너콜백함수document.getElementById('버튼')메소드이므로 해당 메소드를 감싼 button 요소 라는 객체this가 되는 것입니다.

// 정확한 코드는 아니고 이해하기 쉽게 예를 들음

버튼 = {
	addEventListener: function (eventName, e, cb) {
		// 내부가 어떻게 생긴지는 몰라요 🥲	
	}
}

그런데 setTimeout의 콜백 함수는 함수가 호출 될 때 일반 함수로 실행되기에 this전역 객체인 window가 됩니다.

이 경우 결과를 의도한대로 출력하고 싶다면 화살표 함수를 사용하면 됩니다.

<button id="버튼">눌러보세요</button>

document.getElementById('버튼').addEventListener('click', function () {
	setTimeout(() => console.log(this.innerHTML), 1000)
})

화살표 함수는 상위 객체인 이벤트 리스너의 this값을 상속받아 button요소innerHTML눌러보세요 가 1초뒤에 정상적으로 출력됩니다.

콜백함수this에 대해 더 예를 들자면

const 객체 = {
  배열: [1, 2, 3],
  함수: function() {
    console.log(this); 
  }
}

객체.함수(); 
객체.배열.forEach(객체.함수); 

첫번째 코드는 함수객체메소드로 호출된 것이기에 콘솔창에 객체 가 출력됩니다.

하지만 두번째 코드는 forEach 의 콜백함수 파라미터에 객체.함수 가 전달되었죠.
이 경우에 객체.함수 는 단순히 function() {console.log(this);}라는 일반 함수로써 전달된 것이기에 . 앞의 객체메소드로 호출된 것이 아닙니다.
그러므로 this값은 전연 객체를 가리키기 때문에 콘솔창에 window가 3번 출력될 것 이죠.

컨스트럭터의 this

컨스트럭터(constructor)의 this는 컨스트럭터에 의해 탄생한 객체, 인스턴스(instance)입니다.

function 사람(이름, 나이) {
	this.이름 = 이름;
	this.나이 = 나이;
}

const 민수 = new 사람('민수', 15);

console.log(민수);
/*
민수 = {
	이름 = '민수'
    나이 = 15
}
*/

컨스트럭터는 객체생성자인데 말 그대로 객체를 생성할때 사용합니다.
비슷한 객체를 여러개 생성하고 싶을때 유용한데요.
객체를 생성할때는 new 키워드를 사용해서 생성하고 생성된 객체는 인스턴스라고 불립니다.
컨스트럭터의 this가 이 인스턴스입니다.

사람 함수에서 사용된 this.이름 의 this는 새로 생성될 인스턴스를 뜻하니 새로 생성될 객체의(.)이름 이라고 해석하셔도 무방합니다.

정리

자바스크립트의 this에 대해서 알아보았습니다.
this는 참 어렵고 복잡하다고 생각되는 키워드인데요...🥲
존재하는 공간에 따라 역할이 바뀌는 것을 보니 우리와 비슷하다고도 생각이 드네요.
우리도 어떤 회사의 직원, 누군가의 친구, 부모님의 자식이잖아요?
this는 참 요상하고도 매력적인 문법인 것 같습니다 😁

profile
프론트엔드 개발자

0개의 댓글