무브라더

[JavaScript] this 바인딩 본문

Programming/JavaScript

[JavaScript] this 바인딩

동스다
반응형
SMALL

this 라는 개념이 애매하고 헷갈려서 제대로 정리를 해보려고 한다.

https://nykim.work/71

 

[JS] 자바스크립트에서의 this

this는 이것을 뜻합니다! (그러니까 '이게' 뭐죠...... 😵) 자바스크립트 내에서 this는 '누가 나를 불렀느냐'를 뜻한다고 합니다. 즉, 선언이 아닌 호출에 따라 달라진다는 거죠. 그럼 각 상황별로 th

nykim.work

위 게시글을 통해 this 의 역할에 대해서 알아봤는데 보면서 이해가 안된 부분만 정리해보았다.

this

 1. 단독으로 쓴 this

 2. 함수 안에서 쓴 this

 3. 메소드 안에서 쓴 this

 4. 이벤트 핸들러 안에서 쓴 this

 5. 생성자 안에서 쓴 this

 6. 명시적 바인딩을 한 this

 7. 화살표 함수로 쓴 this

 

함수 호출에 따른 this 바인딩

자바스크립트는 함수 호출 방식에 의해 tihs에 바인딩 될 객체가 결정된다.

함수 실행 컨텍스트에서는 this 는 함수가 어떻게 호출됐는지에 집중해서 파악하면 된다.

 

함수 선언식

함수 선언식 안에서 this는 global 객체를 의미한다. (선언이 되어있는 함수에서의 this)

함수 선언식은 함수가 호출,실행 될 때 this가 동적으로 결정된다.

 

그래서인지 함수 선언식이 내부함수에서 선언될 경우 this는 항상 global, window 처럼 전역객체에 바인딩된다.

이러한 바인딩을 해결하기 위한 방법으로는

  • this를 사용하려는 객체에서 사전에 let that = this 처럼 변수로 선언해서 사용하기
  • apply, call, bind 메소드를 사용해 this 바인딩하기
const obj = {
  name: "dong",
  getName: function () {
    console.log(this); //obj
    const that = this;
    setTimeout(function () {
      console.log(this); // window
      console.log(that); //obj
    });
  },
};

arrow function

화살표 함수는 this 바인딩할 객체가 선언할 때 정적으로 결정된다. 즉 언제나 상위 스코프의 this를 가르킨다.(Lexical this)

 

위 함수 선언식과 같은 예제지만 내부함수임에도 화살표 함수는 상위 스코프의 this를 가르키고 있다.

여기서 상위 크소프는 getName 메소드이다.

 

* getName 메소드는 함수 선언식이기 때문에 호출하지 않으면 this는 undefined이다. 아래 코드예제를 구분해서 살펴보자

 

- getName() 호출 전

let a;
const obj = {
  name: "kyle",
  getName: function () {
    a=this
    console.log(this); // undefined
    setTimeout(() => {
      console.log(this);
    });
  },
};
console.log(this) // window

- getName() 호출 후

let a;
const obj = {
  name: "kyle",
  getName: function () {
    a=this
    console.log(this); //1
    setTimeout(() => {
      console.log(this); //3 * setTimeout 사용으로 제일 마지막 실행
    });
  },
};
obj.getName()
console.log(this) //2

 

 

생성자 함수를 사용할 때 this 바인딩

 

생성자 함수는 new 연산자를 붙여서 호출해 객체를 생성하는 함수이다. (암묵적으로 맨 앞글자를 대문자로 사용)

function Person(name) {
  this.name = name;
  console.log(this);
}

const dong = new Person("dong"); //Person { name: 'dong' }
console.log(dong.__proto__); //Person{}
const dongs = Person("dongs"); // Window global Object

new 연산자와 생성자 함수를 호출하면

 

1. 빈 객체를 생성하고 이 객체에 this 바인딩한다.

2. 빈 객체는 생성자함수의 prototype 프로퍼티가 가르키는 객체를 자신의 프로토타입 객체로 설정한다.

3. 빈 객체에 this를 이용해 프로퍼티, 메소드를 생성해 추가한다.

4. 객체를 반환한다.

 

객체 리터럴 vs 생성자 함수

둘의 차이는 각자의 프로토타입 객체가 다르다.

  • 객체 리터럴 : Object.prototpye
  • 생성자 함수 : 생성자함수.prototype

 

addEventListener 사용시 콜백함수의 this

 

addEventListener 를 사용해서 콜백 함수를 호출할 때 콜백함수는 addEventListener를 호출하는 객체가 this로 바인딩 되어 들어간다. 그러지 않기 위해서는 콜백함수를 화살표 함수로 작성하거나 bind로 this를 바인딩하는 방법이 있다.

class Event {
  init() {
    div.addEventListener("click", this.sayThis);
    div.addEventListener("click", this.sayThat);
    div.addEventListener("click", this.useBind.bind(this));
  }
  sayThis() {
    console.log("함수 선언식", this); // div
  }
  sayThat = () => {
    console.log("화살표 함수", this); //Event
  };
  useBind() {
    console.log("함수 선언식 with bind", this); //Event
  }
}

sayThat 에서 화살표 함수를 이용할 때 문제점이 있는데 

 

Event의 prototype property가 가르키는 객체에 화살표 함수로 선언된 sayThat은 포함되지 않는다.

 

화살표함수는 메소드로 사용 할 수 없기 때문이다! (메소드는 객체의 프로퍼티로 있는 함수를 의미)

 

그러면 만약 Event라는 클래스를 상속할 경우 override에 대한 번거로움을 유발시킨다.

 

setTimeout

setTimeout은 웹브라우저에서만 사용이 가능한 메소드이다. 이러한 웹브라우저에서만 사용이 가능한 메소드들은 window에 this가 자동으로 바인딩이 된다. 그렇다면 바로 위에서 설명한 것처럼 전역 바인딩을 원하지 않을때 addEventListener 처럼 bind 또는 함수 표현식으로 작성해야한다.

반응형
LIST
Comments