본문 바로가기
Front-end/Javascript

[JS] this와 bind() 메서드, 그리고 정적 / 동적 문맥

by whatamigonnabe 2022. 5. 5.

 

작업을 하다 this / bind() 대한 이해가 없어 벽에 부닺혀 짧게 나마 얻게 된 내용을 정리하려고 한다.

 

this는 쓰여진 상황에 따라 다르게 동작하는 아주 고약한 놈이다.

그 상황에는 크게 3가지가 있다.

 

1. 기본
백지 스크립트에서 this를 쓰면 전역개채인 window를 참조한다.
그럼 함수 안에서 this를 쓴다면?
그래도 window를 참조한다.

 

2. 생성자(constructor) 안
생성자 안에서는 클래스의 맴버를 정의하거나, 클래스의 멤버를 가리킨다.

Class A {
	constructor() {
    	this name = 'gildong'
        this.getName(); // 같은 클래스 내의 함수에 접근하려면, this를 붙여야함
    }
    
    getName() {
    	console.log(this.name);
    }

}

 

3. 객체 메서드 안
매서드 안에서 this를 사용하면, 아래와 같이 this를 호출한 객체를 참조한다.

const a  = {
	name: 'gildong',
    getName: function() {
    	console.log(this.name);
    }
}

a.getName(); // gildong 출력

     그럼 다음과 같은 상황은 어떨까?

const a  = {
	name: 'gildong',
    getName: function() {
    	console.log(this.name);
    }
}

const b = {
	name: 'nabi',
    _getName: a.getName
}

b._getName(); // nabi 출력

 

이때 이해해야는 것이 '정적 / 동적  문맥'이다.

 

정적 문맥이란 코드를 정의한 시점의 문맥이고,

동적 문맥이란 코드가 실행되는 시점의 문맥이다.

 

위에서 살펴본 this가 가장 대표적으로 정적 문맥을 참조한다. 아래의 예시를 살펴보자.

const b = 'nabi';
const a  = {
	name: 'gildong',
    getName: function() {
    	console.log(this.name);
    }
}

setTimeout(a.getName, 1); // nabi 출력

위의 결과는 무엇일까? 

'nabi'가 출력된다. 왜냐면 setTimeout 함수는 '비동기처리'의 대표적인 예시로 인자로 넘겨 받은 함수를 다른 공간에 저장해 놓은 수 모든 코드가 실행되고 난 뒤에 실행되는데,

그래서 setTimeout의 인자로 넘겨준 함수가 실행된 시점의 this는 전역 객체인 window이기 때문이다.

 

그럼 '동적 문맥'에서 작동하는 this를 코드를 정의한 시점인 '정적 문맥'에서 작동하게 하려면 어떻게 하면 될까?

그때 필요한 것이 bind() 메서드이다.

이 메서드는 코드를 정의할 때 this를 명시적으로 정하게 해준다.

 

const b = 'nabi';
const a  = {
	name: 'gildong',
    getName: function() {
    	console.log(this.name);
    }
}

setTimeout(a.getName.bind(a), 1); // gildong 출력

위와 같이 함수.bind(this로 명시할 대상)으로 작성해주면, 정적 문맥으로 작동하게 된다!

 

그러면 다음과 같은 상황 윈도우 창 크기를 조절하면 어떻게 될까? 이벤트핸들러도 비동기 처리이다.

Class A {
	constructor() {
    	this name = 'gildong'
        this.getName(); // 같은 클래스 내의 함수에 접근하려면, this를 붙여야함
        
        
    }
    
    window.addEventListener('resize', () => {
		this.getName.bind(this);
	}, false);
    
    getName() {
    	console.log(this.name);
    }

}

정답은 무시된다..(?)

왜냐면 this의 중요한 기능 중 하나를 놓치고 있었는데 그것은 '화살표 함수 내에서 사용한 this는 정적 문맥에서 작동한다'는 것이다.

또 위와 같이 쓰면 무시한다는 설정을 찾을 수 있었다...(https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this)

따라서 정상적으로 코드를 다시 작성하면, 아래와 같다!

Class A {
	constructor() {
    	this name = 'gildong'
        this.getName(); // 같은 클래스 내의 함수에 접근하려면, this를 붙여야함
        
        
    }
    
    window.addEventListener('resize', () => {
		this.getName();
	}, false);
    
    getName() {
    	console.log(this.name);
    }

}

그럼 너무 놀라서 길게 작성해버렸는데,,, 역시 코딩은 왜 틀렸는지 찾아가는 과정인 것 같다ㅎㅎㅎ