본문 바로가기
Javascript

[JS] 화살표 함수에서의 "this" 자동 바인딩

by SeanK 2021. 12. 6.

 

 

 

React 관련 포스팅에서 화살표 함수에서 this는 자동으로 바인딩된다고 설명을 했었는데, 

 

이것이 의미하는 것은 무엇인지 그리고 관련해서 좀 더 Deep 하게 들어가 보자. 

 

이것과 관련해서 아래 블로그를 번역하여 옮겼으니 참조하시길 바란다. 

 

출처: https://javascript.plainenglish.io/this-binding-in-es6-arrow-function-70d80e216238

 

How “this” binds in regular functions and arrow functions in JavaScript

Arrow syntax automatically binds this to the surrounding code’s context…but what does this mean?

javascript.plainenglish.io

 

Arrow syntax automatically binds this to the surrounding code's context.

 

화살표 함수는 주변 코드의 문맥에 따라 자동적으로 this를 바인딩한다. 

 

이것이 어떤 뜻인지 설명하도록 하겠다. 그러기 위해서 우선 화살표 함수를 사용함으로써 해결할 수 있는 문제가 무엇인지 이해할 필요가 있다. 

 

화살표 함수 대신 일반 함수 식을 사용하는 시나리오를 가정하겠다. 

 

var Person = function(personName, age){
	this.personName = personName;
    this.age = age;
    this.getDetails = function(){
    
    	callback = function(){
        	console.log('Name: '+this.personName+' , Age: '+this.age);
         }
            
            setTimeout(callback,3000);
        }
}

var person1 = new Person("Chandler", 25);
person1.getDetails();

 

위의 Person 함수는 생성자 함수이다. person1이라는 객체를 아래의 키워드로 생성하고 있다.

 

var person1 = new Person('Joey Smith', 25);

 

1. 위 코드가 실행되면 생성자 함수 Person이 호출되고, personName, age, 그리고 getDetails함수를 포함하는 this.property_name을 이용하여 빈 객체의 특성을 세팅한다. 그리고 생성자는 암묵적으로 person1 변수에 저장된 한 객체를 리턴하게 된다. 

 

2. 따라서 유저는 객체 person1에서 멤버 함수인 getDetails를 아래 코드를 통해 호출할 수 있다.

 

person1.getDetails()

 

3. getDetails 함수는 setTimeout을 가지고 있으며 이는 넘겨받은 함수를 특정 시간(두 번째 인자로 넘겨진) 이후에 실행시킨다. setTimeout에 넘겨진 콜백 함수는 this가 참조되고 있는 일반 함수이다.

 

위의 코드가 실행되면 아래와 같은 결과가 나타날 것이다:

 

Name: undefined, Age: undefined

 

name과 age가 모두 undefined가 되었다. 이런!! 이런 결과를 아마 바란 것은 아닐 것이다. 

왜 그럴까?

이러한 예상치 못한 결과가 나오는 이유는 일반 함수에서 this키워드는 함수를 호출한 객채를 나타내기 때문이다. 일반 함수에서 getDetail 함수를 호출하면 this 키워드는 global 객체를 나타내며, 위의 케이스의 경우 window 객체가 될 것이다. 그리고 해당 객체에는 personName이나 age와 같은 변수가 global 객체에 없기 때문에 undefined라고 결과가 나오는 것이다. 

 

그렇다면 실행 스택에서는 어떤 일이 벌어지고 있는 것일까?

우선은 Global Execution Context는 Person함수와 person1 객체를 변수 환경으로 실행 스택에 넣는다. Person 객체는 위에서 설명한 과정을 따라 new 키워드로 생성되고 person에 저장된다. 

 

 

Execution Stack

 

그 후, Global Execution Context는 person1 객체의 멤버 함수인 getDetails 함수를 호출한다. getDetails 함수가 호출되면, execution context가 생성되고 실행 스택 위에 쌓인다. 

 

Execution Stack

 

getDetails 함수는 setTimeout 함수를 가지고 있고, setTimeout 함수는 Callback Queue(일단은 callback이 저장되는 장소라고 생각하자)에 들어가는 콜백 함수를 가진다. 그리고 이 콜백 함수는 Global Execution Context를 제외한 나머지 실행들이 사라지고 나서야 실행된다. 

 

The left side is execution Context and on the right side is the setTimeout function waiting for the specified time to pass

 

스택이 비면 (Global Execution Context를 제외하고) 콜백은 실행이 되고 Execution Context는 아래 그림과 같이 변하게 된다. 따라서 this 키워드는 Global Context를 가리키게 되는 것이다.

 

 

Execution Stack

 

일반 함수 호출 예제에서, this 키워드는 global Context를 가리키게 되고 personName과 age 변수를 찾을 수 없으면 Global Context는 undefined를 반환하게 된다. 

 

따라서 일반 함수 호출의 문제점은 바로 this가 주변 문맥에 따라 자신을 결정하는 것이 아닌, 함수를 호출한 객체를 가르키게 된다는 것이다. 

 

이것을 어떻게 해결할까?

자바스크립트의 모든 함수들은 어떠한 특수 메서드에 모두 접근이 가능하다. bind(), call(), 그리고 apply()가 그 특수 메서드 중의 하나다. 한 가지 방법은 바로 이런 bind(), call(), 그리고 apply()를 이용하는 것이다. 이것들을 이용하면 this가 무엇을 가리키는지 제어할 수 있게 된다. 

 

따라서 이 메서드들을 이용하면 사용자는 Person을 콜백 함수에 바인드 할 수 있고 그러면 문제가 해결된다. 아래 예제가 콜백 함수에서 바인드 메서드를 이용하고 Person에 바인딩하는 예문이다. 

 

var Person = function(personName, age){
	this.personName = personName;
    this.age = age;
    this.getDetails = function(){
    
    	callback = function(){
        	console.log('Name: '+this.personName+' , Age: '+this.age);
        }
        
        newCallback = callback.bind(this);
        
        setTimeout(newCallback, 3000);
    }
}

var person1 = new Person('Chandler',25);
person1.getDetails();

 

비슷하게, apply와 call 메서드도 사용할 수 있다. 

 

근데, 그냥 문법 변경으로 모든 것을 해결할 수 있는데 굳이 이런 많은 문제를 해결할 필요가 있을까요?

 

위와 같은 시나리오에서, 화살표 함수를 쓰면 간단하게 문제를 해결할 수 있다. 

 

콜백 함수에서 일반 함수 대신 화살표 함수를 사용하면 문제는 간단히 해결된다. 아래 코드를 보자. 

 

var Person = function(perosnName, age){
	this.personNAme = personName;
    this.age = age;
    this.getDetails = function(){
    
    	callback = () => {
        	console.log('Name: '+ this.personName+' Age: '+this.age);
        }
        
        setTimeout(callback, 3000);
    }
}

var person1 = new Person('Chandler', 25);
person1.getDetails();

 

위 코드를 실행하면 아래와 같은 결과를 얻을 수 있다. 

 

Name: Chandler, Age: 25

 

기본적으로 화살표 함수에서 this는 화살표 함수가 정의된 객체를 가리킨다. 화살표 함수는 자동적으로 this를 주변 문맥에 맞춰서 자동으로 바인딩된다. 화살표 함수에서 this는 어떻게 호출되느냐가 아닌 주변 문맥에 따라 정의되는 것이다. 

 

 

 

'Javascript' 카테고리의 다른 글

[nodeJs] Yahoo Finance에서 주식 데이터 끌어오기  (0) 2022.01.29
[JS] 날짜 데이터 포맷 변경하기  (0) 2022.01.23
[JS] Event Bubbling and Event Capturing  (0) 2021.12.05
JS require와 import의 차이?  (0) 2021.12.03
JS JSON  (0) 2021.11.16