[modern JS Deep Dive] - 22장 . this

유선향·2025년 1월 18일
0

<modern_JS_Deep_Dive>

목록 보기
23/44

this 키워드

객체는 상태를 나타내는 프로퍼티와 동작을 나타내는 메서드를 하나의 논리적인 단위로 묶은 복합 자료구조이다.

this 의 존재 이유

  • 동작을 나타내는 메서드는 자신이 속한 객체의 상태, 즉 프로퍼티를 참조하고 변경할수 있어야 한다.
  • 이때 메서드가 자신이 속한 객체의 프로퍼티를 참조하려면 먼저 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다.

자신이 속한 객체를 가리키는 식별자 참조

객체 리터럴 방식

  • 메서드 내부에서 메서드 자신이 속한 객체를 가리키는 식별자를 재귀적으로 참조 가능
  • 아래가 가능한 이유는, getTest가 호출되는 시점에는 이미 객체 리터럴의 평가가 완료되어 객체가 생성되었고, 식별자에 생성된 객체가 할당된 이후다.
  • 하지만 자기 자신이 속한 객체를 재귀적으로 참조하는 방식은 바람직하지 않다.
const circle = { 
	radius : 5,
	getTest() {
		return 2 * circle.radius
	}
}
console.log(circle.getTest())

개발자의 의도와 상관없이 발생한 암묵적 전역은 오류를 발생시키는 원인이 될 가능성이 크므로, var,let,const 키워드를 사용하여 변수를 선언한 다음 사용해야 한다.

생성자 함수

  • 생성자 함수를 정의하는 시점에는 아직 인스턴스를 생성하기 이전이므로 생성자 함수가 생성할 인스턴스를 가리키는 식별자를 알 수 없다. 따라서 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 특수한 식별자가 필요하다.
function Circle(r) {
	???.r = r //이시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자를 알수 없다.
}

Circle.prototype.getTest = function () {
	//알수 없다.
	return 2 * ???.r
}

그래서 this 란?

  • 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수다.

  • this 를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.

  • 자바스크립트 엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조할 수 있다.

  • 함수를 호출하면 arguments 객체와 this가 암묵적으로 함수 내부에 전달되고, this도 지역 변수처럼 사용할 수 있다. 단, this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

  • 바인딩

    • 식별자와 값을 연결하는 과정을 의미한다.
    • this 바인딩은 this와 this가 가리킬 객체를 바인딩 하는 것이다.

함수 호출 방식과 this 바인딩

렉시컬 스코프와 this 바인딩의 결정 시기

  • 함수의 상위 스코프를 결정하는 방식인 렉시컬 스코프는 함수 정의가 평가되어 함수 객체가 생성되는 시점에 상위 스코프를 결정한다.
  • this 바인딩은 함수 호출 시점에 결정된다.

1. 일반 함수 호출

  • 기본적으로 this에는 전역 객체가 바인딩 된다. (일반함수의 중첩함수 또한 마찬가지)

strict mode가 적용된 일반함수

  • this = undefined
  • 일반 함수 내부에서는 this를 사용할 필요가 없기 때문
  • 객체의 메서드 내부 or 생성자 함수 내부에서만 의미가 있다.
  • 어떠한 함수라도 일반함수로 호출되면 this 에 전역 객체가 바인딩 된다.

중첩함수, 콜백 함수의 this 가 전역객체를 참조하는 것의 문제점

  • 중첩 함수 , 콜백함수는 보통 외부 함수를 돕는 헬퍼 함수의 역할을 하므로 외부 함수의 일부 로직을 대신하는 경우가 대부분이다.
  • 외부 함수인 메서드와 중첩 함수, 콜백함수의 this 가 일치하지 않는 것은 중첩함수와 콜백 함수를 헬퍼 함수로 동작하기 어렵게 만든다.

중첨, 콜백함수의 this 바인딩을 메서드의 this 바인딩과 일치시키기

  1. 변수에 this 담기
var value. =1 
const obj = {
	value :100,
	foo() {
		const that = this //
		setTimeout(function () {
			console.log(that.value) //100
			}
			...
			
  1. this 를 명시적으로 바인딩 하기
    1. Function.prototype.apply
    2. Function.prototype.call
    3. Function.prototype.bind
  2. 화살표 함수 사용하기

2. 메서드 호출

  • 메서드 내부의 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩 된다는 것이다.
  • 객체의 메서드는 해당 객체에 포함된 것이 아니라 독립적으로 존재하고, 다만 그 함수 객체를 프로퍼티가 가리키고 있을 뿐이다.
  • 따라서 메서드 내부의 this 는 프로퍼티로 메서드를 가리키고 있는 객체와는 관계가 없고, 메서드를 호출한 객체에 바인딩된다.
function Person (name) {
	this.name = name,
	getName(function () {
		return this.name
		})
	}
	
	const me = new Person('Lee')
	
	//getName 메서드 내부의 this 는 me 를 가리킨다.

3. 생성자 함수 호출

  • 생성자 함수 내부의 this 에는 생성자 함수가 생성할 인스턴스가 바인딩 된다.
const test = { 
	r:5,
	getTest(){
		return this.r
	}
}
this === test

4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출

  • 이 세가지 메스드는 모두 Function.prototype의 메서드다. 즉, 이들 메서드는 모든 함수가 상속받아 사용할 수 있다.
function getThis () {
	return this
}
const arg = {a:1}
console.log(getThis()) //window

console.log(getThis.apply(arg))//{a:1}
console.log(getThis.call(arg))//{a:1}

5. Arrow Function

  • 일반 함수처럼 호출한 대상에 따라 상대적으로 변하는 것이 아니라, Arrow Function을 감싸는 정적 범위(Lexical Scope)인 선언되기 직전에 유효한 this 를 갖게 된다.
  • 아래에 returnThis 가 선언되기 직전에 유효한 this 는 window 객체 이다.
const returnThis = () => this;

const obj = {
	name:'obj',
	returnThis: returnThis,
	returnThis2: () => this
};

console.log(obj.returnThis() === window); // true

6. DOM 이벤트 처리

  • 이벤트 처리에 사용한 함수에서 this 는 이벤트를 보낸 요소로 설정 된다.
function checkThis(event) {
	console.log(this === event.currentTarget); // true
}

const element = document.getElementById('something')

element.addEventListener('click', checkThis, false)
함수 호출 방식this 바인딩
일반 함수 호출전역 객체
메서드 호출메서드를 호출한 객체
생성자 함수 호출생성자 함수가 생성할 인스턴스
Function.prototype.apply/call/bind 메서드에 의한 간접 호출Function.prototype.apply/call/bind 메서드에 첫번째 인수로 전달한 객체

0개의 댓글