Language/Javascript (Typescript)

[Javascript] Arrow Function에서의 this / arguments 바인딩 형태

ooeunz 2020. 7. 19. 16:46
반응형

Arrow Function에서의 this 바인딩

일반적으로 Javascript에서의 this는 가장 가까이 있는 객체를 바인딩하게 됩니다. 하지만 화살표 함수에서는 조금 다르게 작동하는데 화살표 함수에서는 일반 함수와 다르게 this와 arguments가 바인딩되지 않습니다.

 

이와 같이 화살표 함수에서는 this 바인딩이 되지 않는 이유는 일반 함수에서는 this 바인딩으로 인한 버그가 발생할 수 있기 때문입니다. 일반적으로 일반 함수에서는 this를 사용하면 호출 시점에 사용된 객체로 바인딩되게 됩니다. 따라서 객체에 바인딩된 일반 함수를 다른 변수에 할당해서 호출하게 되면 버그가 발생하게 됩니다. 아래의 예시를 살펴보겠습니다.

const obj = {
  count: 1,
  increase: function () {
    this.count++;
  },
};

obj.increase();
console.log(obj.count); // 2

const assignNewObject = obj.increase;
assignNewObject();
console.log(obj.count); // 2

코드를 살펴보면 obj 객체 안에 increase라는 일반 함수를 작성하게 됩니다. 이때 함수의 this는 obj 객체를 바인딩하게 됩니다. 때문에 obj.increase(); 를 호출 시 정상적으로 count 값이 증가되는 것을 알 수 있습니다.

 

하지만 assignNewObject라는 새로운 변수에 obj의 increase함수를 할당해줌과 동시에 assignNewObject 함수는 전역객체(window)를 바인딩하게 됩니다. 그래서 assignNewObject(); 함수를 호출하더라도 의도했던 대로 코드가 동작하지 않습니다.

 

이때 만약 increase 함수를 화살표 함수로 작성하게 된다면 어떻게 될까요? 화살표 함수 안에서 사용된 this와 arguments는 자신을 감사고 있는 가장 가까운 일반 함수의 것을 참조합니다. 때문에 increase 함수를 화살표 함수로 작성했다면 this는 처음부터 전역객체 window를 가리키게 되기 때문에 아무리 함수를 호출하더라도 obj.count 값은 변하지 않습니다.

const obj = {
  count: 1,
  increase: () => {
    this.count++;
  },
};

obj.increase();
console.log(obj.count); // 1

const assignNewObject = obj.increase;
assignNewObject();
console.log(obj.count); // 1

 

 

생성자 함수 내부에서 Arrow Function

이번에는 생성자 함수 내부에서 사용되는 화살표 함수에 대해서 살펴보겠습니다. 아래의 코드를 보면 화살표 함수 안의 this는 가장 가까운 일반 함수인 ConstructorSample의 this를 참조하게 됩니다. 여기서 특이한 점은 new 키워드를 이용해서 생성자 함수를 호출하면 this는 생성되는 객체를 참조하게 된다는 점입니다. 따라서 case1과 2에 관계없이 increase함수의 this는 일관되게 new로 생성된 ConstructorSample 객체의 this를 가리키게 되고 count 값은 일관되게 증가되게 됩니다.

function ConstructorSample() {
  this.count = 1;
  this.increase = () => this.count++;
}

// case 1
const obj = new ConstructorSample();
obj.increase();
console.log(obj.count); // 2

// case 2
const increase = obj.increase;
increase();
console.log(obj.count); // 3

 

 

 

setInterval 함수에서의 this 바인딩

setInterval 함수는 지정된 시간이 지나고 인자로 받은 함수를 실행 시키는 함수입니다. 아래의 코드를 실행해보면 obj.count 값이 증가되길 바랐던 의도와는 달리 값이 변하지 않게 됩니다. 그 이유는 setInterval 함수의 인자로 들어간 increase함수는 전역 환경에서 실행되기 때문에 window객체를 가리키기 때문입니다.

function ConstructorSample() {
  this.count = 1;
  setInterval(function increase() {
    this.count++;
  }, 1000);
}

const obj = new ConstructorSample();

 

이와 같은 문제를 해겨하기 위해서 ES5 이하의 환경에서는 (들어보셨을지 모르겠지만) that이라는 약속된 이름의 변수에 클로저를 이용하여 this를 바인딩한 후 접근하는 방식과 같은 편법을 사용하였습니다.

function ConstructorSample() {
  this.count = 1;
  var that = this
  setInterval(function increase() {
    that.count++;
  }, 1000);
}

const obj = new ConstructorSample();

 

 

하지만 화살표 함수를 사용하게 되면 가장 가까운 일반 함수를 자동으로 바인딩하기 때문에 이와 같은 편법을 사용할 필요가 없어졌습니다. 화살표 함수의 this는 setInterval의 동작과 상관없이 obj객체를 참조하기 때문입니다.

function ConstructorSample() {
  this.count = 1;
  setInterval(() => {
    this.count++;
  }, 1000);
}

const obj = new ConstructorSample();
반응형