JS_this 바인딩

박채연·2024년 5월 16일

프론트엔드 기초

목록 보기
9/10

this 란

this는 자기 자신의 참조값을 의미합니다. 다른 언어와 달리 자바스크립트에서 this는 상황에 따라 많이 변합니다. 그래서 더욱 혼란을 가중하곤 합니다.

기본적으로 this는 함수가 '호출 되었을 때' 결정됩니다.

this가 바뀌는 상황

  1. 일반 함수가 호출을 할 때
  2. 메서드로 호출할 때
  3. 생성자 함수로 생성될 때
  4. addEventListener
  5. 2 ~ 4번 경우인데 화살표 함수로 정의가 되었을 때
  6. apply / call / bind 로 this를 바인딩하였을 때

1. 일반 함수가 호출을 할 때

function square(number) {

  console.log(arguments);
  console.log(this);

  return number * number;
}

square(2);

이 때 this는 어떻게 찍힐까요? this는 전역객체인 window(브라우저일 때, Node 환경에서는 global)가 찍힙니다.

2. 메서드로 호출할 때

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    console.log("foo's this: ",  this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    function bar() {
      console.log("bar's this: ",  this); // window
      console.log("bar's this.value: ", this.value); // 1
    }
    bar();
  }
};

obj.foo();

obj foo 함수 내부의 this는 obj를 가리키고 this.value가 obj.value와 같은 말이라 100이 찍힙니다.

하지만 foo 함수의 내부의 bar 함수의 this는 객체를 가르키고 있지 않기 때문에 this가 window에 가리키게 되고 window 객체(전역 객체)에는 value가 1이 정의 되어 있어 1이 찍히게 됩니다.

이처럼 같은 함수 내부라도 호출에 따라 달라집니다.

만약 이 상황에서, bar 내부에도 this를 obj로 활용할려면 어떡해야 할까요?

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    const that = this;
    console.log("foo's this: ",  this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    function bar() {
      console.log("bar's this: ",  that); // obj
      console.log("bar's this.value: ", that.value); // 100
    }
    bar();
  }
};

obj.foo();

이렇게 변수를 이용할 수도 있습니다.

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    console.log("foo's this: ",  this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    function bar() {
      console.log("bar's this: ",  this); // obj
      console.log("bar's this.value: ", this.value); // 100
    }
    bar.call(obj);
  }
};

obj.foo();

이렇게 this 바인딩(call, apply, bind)로 직접 this를 명시할 수도 있습니다.

3. 생성자 함수로 생성될 때

// 생성자 함수
function Person(name) {
  this.name = name;
}

var me = new Person('Lee');
console.log(me); // Person {name: "Lee"}

// new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수로 동작하지 않는다.
var you = Person('Kim');
console.log(you); // undefined

Person 생성자함수의 this는 인스턴트를 가리키게 됩니다. 이 때 주의점은 new 키워드를 붙여야 this가 인스턴스를 가리키게 되고 그렇지 않으면 일반함수처럼 this가 window 객체가 되어 제대로 작동하지 않습니다.

// 생성자 함수
function Person(name) {
  // this = {}; -> 코드 생략
  this.name = name;
  // return this; -> 코드 생략
}

new 연산자를 붙이게 되면 인스턴스가 생성될 때 this라는 빈 객체가 생성되고 이 this가 리턴되도록 설계가 되어 있습니다.

4. addEventListener

const button = document.getElementById('myButton');

button.addEventListener('click', function() {
   console.log(this);	// button 엘리먼트
   this.innerHTML = 'clicked';
});

위의 경우에는 이벤트 발생하는 target이 this에 바인딩이 됩니다.

5. 2 ~ 4번 경우인데 화살표 함수로 정의가 되었을 때

2번의 경우부터 봅시다.

var value = 1;

var obj = {
  value: 100,
  foo: () => {
    console.log("foo's this: ",  this);  // window
    console.log("foo's this.value: ",  this.value); // 1
    function bar() {
      console.log("bar's this: ",  this); // window
      console.log("bar's this.value: ", this.value); // 1
    }
    bar();
  }
};

obj.foo();

3번의 경우 입니다.

Person = (name) => {
  this.name = name;
}

var me = new Person('Lee');
// Uncaught TypeError: Person is not a constructor

4번의 경우입니다.

const button = document.getElementById('myButton');

button.addEventListener('click', () => {
  console.log(this);	// Window
  this.innerHTML = 'clicked';
});

이 3가지의 공통점은 this가 전역객체인 window를 바라본다는 특징이 있습니다. 화살표 함수를 쓰게되면 객체나 인스턴스에 this 바인딩이 되지 않고 전역객체에 바인딩 됩니다.

this를 활용하는 경우에는 가급적 화살표함수를 쓰지 않는 것이 좋습니다.
하지만 이를 역이용해서 객체나 인스턴스에 this 바인딩을 하고싶지 않을 때는 화살표함수를 쓰도록 합니다.

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    console.log("foo's this: ",  this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    const bar = () => {
      console.log("bar's this: ",  this); // obj
      console.log("bar's this.value: ", this.value); // 100
    }
    bar();
  }
};

obj.foo();

예를 들어 bar 함수는 foo 함수의 내부함수로 bar 내부에 this를 쓰지 않고 foo의 this를 활용하고 싶은데 간단히 활용하는 방법은 bar를 화살표 함수로 바꾸는 것입니다.

6. apply / call / bind 로 this를 바인딩하였을 때

3가지 모두 this를 바인딩한다는 똑같은 기능을 합니다.

사용법에 차이가 있는데

// apply(this 바인딩 객체, [함수 인자들])
// call(this 바인딩 객체, 함수 인자1, 함수 인자2... )
// bind(this 바인딩 객체)(함수 인자1, 함수 인자2...)
var Person = function (name) {
  this.name = name;
};

var foo = {};

// 1. apply
Person.apply(foo, ['name']);
// 2. call
Person.apply(foo, 'name');
// 3. bind
Person.apply(foo)('name');

console.log(foo); // { name: 'name' }

참고

this
화살표 함수와 this의 바인딩

profile
기록장입니다.

0개의 댓글