[JavaScript] 자바스크립트 this란?

김기완·2021년 2월 5일
0
post-thumbnail

'this' keyword

객체지향언어에는 this라는 키워드가 대부분 존재합니다.
자바스크립트에도 this가 존재하는데, 이는 다른 객체지향언어와는 다르게 동작합니다.
다른 언어들처럼 함수를 선언할 때 this에 바인딩할 객체가 결정되는 것이 아니고, 함수가 호출되는 방식에 따라 동적으로 바인딩할 객체가 결정됩니다. 이는 자바스크립트 인터프리터가 코드를 실행하면서 생성하는 Execution Context에 기인합니다.

function foo() {
  const a = 2;
  this.bar();
}

function bar() {
  console.log(this.a);
}

foo();		//undefined

위의 예시에서의 foo의 this는 함수의 Lexical Scope가 아닌 Global Scope를 참조하고 있습니다.
이는 Global Scope가 foo의 Execution Context이기 때문입니다.

How 'this' works in JavaScript

Execution Context에는 Variable Object, Scope Chain, 그리고 this 에 대한 정보를 저장합니다.
Execution Context는 함수 호출 시 새로 생성되며, 동시에 this 값을 정합니다. 함수가 호출될 때, ECMAScript는 Arguments List와 thisArg 객체를 전달한다. 이 때 아래의 과정을 통해 this 값을 결정합니다.

  1. strict mode에서 정의된 함수일 경우, thisthisArg가 된다.
  2. thisArg가 null | undefined 일 경우, this는 global Object가 된다.
  3. Type(thisArg) 값이 객체가 아닌경우, thistoObject(thisArg) 가 된다.
    • Type() 함수는 ECMAScript 내부 함수로, 변수의 Type을 리턴합니다.
    • toObject() 함수는 변수를 Boolean, Number, String, Object 형으로 변환합니다.
  4. 위의 과정을 거치고도 this 값이 정해지지 않았다면, thisthisArg가 된다.

call, apply, bind 모두 thisArg 수정함으로써 this 값을 바인딩하는 것입니다.
그렇다면, thisArg는 어떻게 결정되는 것일까? 이는 함수 호출 과정의 6번 단계와 관계가 있습니다.

  1. Type(ref) 값이 reference 라면,

    1. isPropertyReference(ref) 를 통해 refobject | primitive wrapper object(Stirng, Boolean, Number 등의 객체) 라면 thisArggetBase(ref) 값이 된다.
    2. 그렇지 않다면, thisArggetBase(ref) 값의 ImplicitThisValue() 값이 된다.

위의 과정만 봐서는 this가 언제 어떻게 바인딩되는지 알기 어렵습니다. 그래서, 흔히 발생하는 케이스를 통해 간단한 규칙을 소개하겠습니다.

Simple Rules to ‘this’ in JavaScript

  1. new 키워드와 함께 함수를 호출하면,this는 아예 새로운 객체가 된다.
function Person(age) {
  console.log(this)
  this.age = age
  console.log(this)
}

const person = new Person(22)
// {}
// { age: 22 }
  1. apply, call, bind 가 함수의 호출/생성에 사용되면, this는 인수로 전달된 객체가 된다.
function foo() {
  console.log(this)
}

const obj {
  value: 5
}

const example = foo.bind(obj)
    
example()		// { value: 5 }
foo.call(obj)	// { value: 5 }
foo.apply(obj)	// { value: 5 }
  1. obj.method()와 같이 함수를 호출하면, thisobj가 된다.
const obj = {
  value: 5,
  print: function() {
    console.log(this)
  }
}
    
obj.print()	// { value: 5, print: f }
  1. 자유 함수(위의 조건 없이)로 호출되면, this는 전역 객체(브라우저에서는 window)가 된다. 단,strict mode에서는 undfined 가 된다.
function foo() {
  console.log(this);
}

//브라우저에서 호출되면
foo()	// Window { stop: f, open: f, alert: f, ... }

// 이 규칙은 3번 규칙과 동일합니다. 객체의 메소드로 선언되지 않은 함수는 자동으로 전역 객체의 property가 됩니다.
// foo()와 같이 함수를 호출하는 것은, window.foo()로 해석됩니다.
  1. 위의 4가지 규칙 중, 다수가 적용되면 상위 규칙이 승리한다.
  2. ES6에 새로 정의된 화살표 함수인 경우, 위의 규칙을 무시하고 Lexical Scope를 따라 상위 스코프의 this 값을 받는다.



참고자료

1개의 댓글

comment-user-thumbnail
2021년 2월 6일

이번 글도 잘 보고 갑니다~

답글 달기