fffo

자바스크립트에서의 this 키워드 본문

Programming/Javascript

자바스크립트에서의 this 키워드

gggs 2021. 11. 8. 16:46

this 키워드

this 키워드는 자기 자신이 속한 객체나 속할 객체를 가리키기 위한 자기 참조 변수입니다. 메서드에서 자신이 속한 객체의 프로퍼티를 참조하기 위해 자신이 속한 객체를 가리키거나 생성자 함수에서 자신이 만들 인스턴스를 가리키는 식별자를 참조하기 위해 사용합니다.

this는 자바스크립트 엔진에 의해 암묵적으로 생성되어 함수 호출 방식에 의해 동적으로 바인딩 됩니다. 크게 네 가지로 나누어 볼 수 있습니다. 일반 함수 호출, 메서드 호출, 생성자 함수 호출, 그리고 간접 호출 이렇게 네 가지로 각각의 호출 방식에 의해 this가 가리키는 값은 동적으로 바인딩 됩니다.

메서드 호출 시 this

메서드란 보통 객체에 묶여있는 함수를 말하는데 여기서 말하는 메서드는 조금 더 구체적인 범위를 가지고 있습니다. ES6 사양 이후에 나온 메서드 축약 표현으로 정의된 함수만을 의미합니다.

메서드 호출 시의 this는 메서드를 호출한 객체가 this에 바인딩 됩니다. 이 때 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩 됨을 유의해야 합니다.

const test = {
  x: 456,
    testMethod() {
    console.log(`My x is ${this.x}.`);
  }
}

test.testMethod(); // My x is 456.

생성자 함수 호출 시 this

생성자 함수 호출 시의 this는 미래에 생성할 인스턴스가 this에 바인딩 됩니다.

function Person(name) {
    this.name = name;
    this.greeting = function () {
        console.log(`Hi. I'm ${name}.`);
    }
}

const p1 = new Person('dlwlrma');
p1.greeting(); // Hi. I'm dlwlrma.

일반 함수 호출 시 this

다음으로 일반 함수 호출시에는 this에 전역 객체가 바인딩 됩니다. 여기서 일반 함수는 메서드 내에서 정의한 중첩 함수, 일반 함수로 호출된 콜백 함수도 포함됩니다. 객체를 생성하지 않는 일반 함수에서 this는 의미가 없고 혼란만 가중되므로 strict mode 적용 시 this에 undefined가 바인딩 됩니다.

그런데 이러한 this의 성질 때문에 헬퍼 함수로 사용되는 중첩 함수나 콜백 함수의 this는 원래의 스코프에서 가지는 this와 다르기 때문에 문제가 생길 수 있습니다. 이를 해결하는 방법으로는 Function.prototype.apply/call/bind 메서드와 ES6 이후에 나온 화살표 함수가 있습니다.

apply/call/bind메서드

apply/call/bind메서드는 모두 Function.prototype의 메서드로 셋 모두 공통적으로 첫 번째 인자로 this에 바인딩할 객체를 전달합니다. 이로 인해 일반 함수로 호출 되었던 함수들도 this에 전역객체가 아닌 의도한 객체를 바인딩 할 수 있습니다. 각각의 함수의 차이점은 다음과 같습니다. apply와 call은 함수 호출까지 하지만 bind는 바인딩만 할 뿐, 함수를 따로 호출하지는 않습니다. apply는 함수에게 전달할 인수 배열 혹은 유사배열 객체를 두 번째 인자로 받는 반면 call은 두 번째 인자 이후부터 함수에게 전달할 인자를 각각 받습니다.

화살표(arrow) 함수

그렇다면 헬퍼 함수를 사용할 때나 콜백 함수에서는 매번 바인딩 메서드를 사용해야 할까요? ES6 이후에서는 화살표 함수라는 문법을 통해 this바인딩을 좀 더 쉽게 할 수 있습니다. 화살표 함수와 기존 함수는 몇 가지 차이점이 있습니다. 화살표 함수 자체의 this 바인딩을 갖지 않습니다. 이러한 특징 덕분에 스코프 체인을 통해 상위 스코프의 this값을 가져올 수 있습니다. 이 외에도 화살표 함수는 기존 함수와 동일하게 호출 가능하지만 함수 선언문으로 정의할 수 없고 함수 표현식으로만 정의해야 합니다. 화살표 함수는 인스턴스를 생성 할 수 없는 non-constructor이고 중복된 매개변수 이름을 선언 할 수 없는 엄격한 함수입니다.

이벤트 핸들러에서의 this

비동기로 처리되는 이벤트 핸들러의 this는 핸들러가 attached된 eventemitter를 참조합니다.

const Ev = require('events');
const myEmitter = new Ev();
myEmitter.on('ppap', function () {
  console.log('test 1 : ', this);
  console.log('test 2 : ',this === myEmitter);
});

myEmitter.emit('ppap');

setTimeout(function(){
  console.log('test 3 : ', this);
}, 0);


/*
test 1 :  EventEmitter {
  _events: [Object: null prototype] { ppap: [Function (anonymous)] },
  _eventsCount: 1,
  _maxListeners: undefined,
  [Symbol(kCapture)]: false
}
test 2 :  true
test 3 :  Timeout {
  _idleTimeout: 1,
  _idlePrev: null,
  _idleNext: null,
  _idleStart: 43,
  _onTimeout: [Function (anonymous)],
  _timerArgs: undefined,
  _repeat: null,
  _destroyed: false,
  [Symbol(refed)]: true,
  [Symbol(kHasPrimitive)]: false,
  [Symbol(asyncId)]: 4,
  [Symbol(triggerId)]: 1
}
*/

 

Comments