자바스크립트 this

냐하호후·2022년 5월 6일
0

자바스크립트 함수는 호출될 때 매개변수로 전달되는 인자값 외에 this를 암묵적으로 전달 받는다.

함수 호출 방식

자바스크립트의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다. 다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다

함수 호출

기본적으로 this는 전역객체(Global object)에 바인딩된다. 전역함수는 물론이고 심지어 내부함수의 경우도 this는 외부함수가 아닌 전역객체에 바인딩된다.

function foo() {
  console.log("foo's this: ",  this);  // window
  function bar() {
    console.log("bar's this: ", this); // window
  }
  bar();
}
foo();

또한 메소드의 내부함수일 경우에도 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
    function bar() {
      console.log("bar's this: ",  this); // window
      console.log("bar's this.value: ", this.value); // 1
    }
    bar();
  }
};

obj.foo();

callback함수일 경우에도 this는 전역객체에 바인딩한다.
내부함수는 일반 함수, 메소드, 콜백함수 어디에서 선언되었든 관게없이 this는 전역객체를 바인딩한다.

내부함수의 this가 전역객체 참조를 피하기 위해서는 외부 함수에서의this를 다른 변수에 선언해두고 그 변수를 이용하는 방법이 있다.

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

obj.foo();

Strict mode
스크립트 코드 맨 상단에 'use strict'를 쓰면 strict mode를 쓸 수 있다.
strict mode에서 this는 무조건 undefined이다.

메서드 호출

함수가 객체의 값이면 메소드로서 호출된다. 이때 메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩된다.

생성자 함수 호출

new 연산자와 함께 생성자 함수를 호출하면 생성자로 인해 생성된 새로운 객체를 가리킨다.

call,apply,bind 호출

this를 바인딩할 수 있는 메소드 call,apply,bind가 있다.
bind가 call,apply와 다른 점은 함수를 호출하지 않는 점이다.

Function.prototype.call()

func.call(thisArg[, arg1[, arg2[, ...]]])

let person1 = {
    name: 'Jo'
};

let person2 = {
    name: 'Kim',
    study: function() {
        console.log(this.name + '이/가 공부를 하고 있습니다.');
    }
};

person2.study(); // Kim이/가 공부를 하고 있습니다.

// call()
person2.study.call(person1); // Jo이/가 공부를 하고 있습니다.

첫 번째 매개변수 thisArg는 함수의 this를 지정시켜준다. 두번째부터는 함수에 호출되어야하는 인자가 들어간다.

Function.prototype.apply()

func.apply(thisArg, [argsArray])

call()과 달리 apply()는 두번째 매개변수를 배열 형태로 넣어야한다.

Function.prototype.bind()

func.bind(thisArg[, arg1[, arg2[, ...]]])

bind()는 함수를 실행하지 않고 대신 bound함수를 리턴한다.
변수에 할당해서 변수를 호출하는 형태로 사용된다.

let person1 = {
    name: 'Jo'
};

let person2 = {
    name: 'Kim',
    study: function() {
        console.log(this.name + '이/가 공부를 하고 있습니다.');
    }
};

person2.study(); // Kim이/가 공부를 하고 있습니다.

// bind()
let student = person2.study.bind(person1);

student(); // Jo이/가 공부를 하고 있습니다.

화살표 함수

화살표 함수 내부에는 this가 없다.

JavaScript에서는 어떤 식별자(변수)를 찾을 때 현재 환경에서 그 변수가 없으면 바로 상위 환경을 검색합니다. 그렇게 점점 상위 환경으로 타고 타고 올라가다가 변수를 찾거나 가장 상위 환경에 도달하면 그만두게 되는 것이죠. 화살표 함수에서의 this 바인딩 방식도 이와 유사합니다. 화살표 함수에는 this라는 변수 자체가 존재하지 않기 때문에 그 상위 환경에서의 this를 참조하게 됩니다.

화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없다.

화살표 함수를 사용해서는 안되는 경우

상위 환경의 this를 참조한다는 점이 문제가 될 수도 있다. 아래 같은 경우이다.

메소드

const cat = {
  name: 'meow';
  callName: () => console.log(this.name);
}

cat.callName();	// undefined

이 같은 경우, callName 메소드의 this는 자신을 호출한 객체 cat이 아니라 함수 선언 시점의 상위 스코프인 전역객체를 가리키게 된다.
일반 함수를 사용하면 메소드로 호출하면 자신을 호출한 객체를 가리킨다. 일반 함수를 쓰자

생성자 함수

화살표 함수를 생성자함수로 사용하면 에러가 난다. 생성자 함수로 사용할 수 없게 만들어졌다.

addEventListener()함수의 콜백함수

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

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

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

원래 addEventListener의 콜백함수에서는 this에 해당 이벤트 리스너가 호출된 엘리먼트가 바인딩되도록 정의되어 있다. 이처럼 이미 this의 값이 정해져있는 콜백함수의 경우, 화살표 함수를 사용하면 기존 바인딩 값이 사라지고 상위 스코프(이 경우엔 전역 객체)가 바인딩되기 때문에 의도했던대로 동작하지 않을 수 있다. 물론 상위 스코프의 속성들을 쓰려고 의도한 경우라면 사용할 수 있다.

참고

this의 4가지 역할

profile
DONE is better than PERFECT

0개의 댓글