Skip to content

Instantly share code, notes, and snippets.

@snaag
Created May 13, 2020 09:45
Show Gist options
  • Save snaag/858bc0a8623bab7cf219aa971dda4006 to your computer and use it in GitHub Desktop.
Save snaag/858bc0a8623bab7cf219aa971dda4006 to your computer and use it in GitHub Desktop.

들어가며

실행 컨텍스트에 관한 지난번 자료에서 this는 실행 컨텍스트에 따라 달라진다 라는 내용을 간단하게 언급했었다.

그 때는 왜 달라지는지 에 대해서 언급을 했었다. 이번에는 어떻게 달라지는지 에 대한 내용이다.

혹시나 링크를 타고가지 않을 누군가를 위해 간단하게 말해보자면,

Execution context 가 만들어질 때 this 가 바인딩이 되기 때문이다. 그러니까 실행 중에 결정이 된다는 말이다.

추가적으로 this 를 찾다보면 this는 Lexical Scope 와 아무런 관계가 없다 라는 것을 종종 볼 수 있다. 나는 이 말을 Execution context 가 만들어질 때 activation object(variable object) 안에서 thisparameter 가 아예 별개의 property 로써 존재하기 때문이라고 생각한다.

앞에 내용을 읽고 이런 생각이 들 것이다.

음 그렇다면 this 는 동적으로 바인딩이 되겠구나.

동적으로 바인딩이 된다면... 누가 호출했냐에 따라 바인딩이 달라지겠지?

맞아!

  • 책 You Don't Know JS (2) 를 참고하였다.

호출부에 따른 this의 바인딩

각각의 바인딩 방식은 이름을 갖고 있지만, 나는 개인적으로 이름 때문에 처음에 this 의 바인딩을 접했을 때 더 혼란스러웠기 때문에 이름과 코드의 상황(?) 을 같이 정리해봤다.

기본 바인딩(Default binding) 아무것도 명시하지 않았을 경우

아무것도 명시하지 않았을 경우 this전역 객체 혹은 undefined 에 바인딩되는 것을 말한다.

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

var a = 2;
foo(); // 2

엄격 모드에서는 thisundefined 가 바인딩되고, 그렇지 않은 경우(위 코드)에는 this전역 객체 가 바인딩된다.

암시적 바인딩(Implicity binding) context가 있는 경우

obj.foo() 와 같이 context가 있는 경우, 그 context에 this 가 바인딩되는 것을 말한다.

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

var obj = {
  a: 2,
  foo: foo
}

obj.foo(); // 2

명시적 바인딩(Emplicity binding) 바인딩 할 객체를 명시하는 경우

call() 또는 apply() 를 사용하여 어떤 객체를 this 로 꼭 바인딩 시키는 것을 말한다.

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

var obj = {
  a: 2
};

foo.call(obj); // 2

하드 바인딩

명시적 바인딩을 이용하여, 항상 어떤 객체로 바인딩 시키는 것 을 말한다.

var obj = {
  a: 2
};

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

var bar = function() {
  foo.call(obj);
}

bar(); // 2
bar.call(window); // 2

그래서 이러한 특성을 사용하여 인자를 넘기고 반환 값을 돌려받는 창구가 필요할 때 주로 쓰인다.

아래 코드는 어떤 객체의 this 를 고정시켜주는 bind() 라는 함수이다.

function foo(something) {
  console.log(this.a, something);
  return this.a + something;
}

function bind(fn, obj) {
  return function() {
    return fn.apply(obj, arguments);
  }
}

var obj = {
  a: 2
};

var bar = bind(foo, obj); // bar는 foo()의 this에 obj를 바인딩한 함수를 할당 받는다.

var b = bar(3); // 2 3 
console.log(b); // 5

new 바인딩 new를 사용해서 객체를 만든 경우

function foo(a) {
  this.a = a;
}

var bar = new foo(2);

console.log(bar.a); // 2

var bar = new foo(2); 를 자세히 보자.

new foo(2); 를 하게 되면 새로운 object 가 생긴다. 이 때 이 새로운 objectthis 에다가 bar 를 바인딩해준다.

new-binding-example.png

이 경우, prototype chaining 이 어떻게 되는지를 간단하게 보고 가자.

이 때 이런 코드가 있을 때, 호출되는 것은 생성자 함수 가 아니라, 함수 foo()constructor 를 호출하는 것이다. 그러니까 생성자 함수를 호출하는 것이 아니라, 함수 foo()의 생성자를 호출 하는 것이다.

(이를 통해 barfoo()의 prototype 객체 에 접근할 수 있다)

this-binding-example.png

정리

this함수 호출 시 3가지 방법 으로, 그냥 호출 시 1가지 방법 으로 바인딩이 된다.

함수 호출 시 에는 아래의 방법으로 바인딩이 된다.

  1. 암시적 바인딩 var bar = obj.foo();
  2. 명시적 바인딩 var bar = foo.call(obj);
  3. new 바인딩 var bar = new foo();

그냥 호출 시 아래의 방법으로 바인딩이 된다.

  1. var bar = foo();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment