본문 바로가기

자바스크립트🔥

ES6 / 헷갈리는 그 이름 this 1편 / 함수호출

일단 HTML5 CSS3로 코드를 접한 나는 JS배우기 시작하고나서 하루하루가 쥰내빡치는 일들의 연속이었다.

그 중 지금도 헷갈리는 this를 지금 이 시간에 정리해보자.

 

Js에서함수는 호출될 때 매개변수로 전달되는 인자값 이외에 arguments 객체와 this를 암묵적으로 전달받는다.

 

Js의 경우 함수호출방식에 따라 this에 바인딩할 객체가 동적으로 결정됨.

함수가 어떻게 호출되었는가에 따라 this에 바인딩할 객체가 결정된다는 뜻임.

 

( 함수의 상위 스코프를 결정하는 방식인 렉시컬 스코프(Lexical Scope)는 함수를 선언할 때 결정됨.

this 바인딩과 헷갈리지 않도록 주의해야함. )

 

함수를 호출하는 방식은 아래와 같이 다양함.

  1. 함수호출
  2. 메소드 호출
  3. 생성자 함수 호출
  4. apply/call/bind 호출
var foo = function () {
  console.dir(this);
};

// 1. 함수 호출
foo(); // window
// window.foo();

// 2. 메소드 호출
var obj = { foo: foo };
obj.foo(); // obj

// 3. 생성자 함수 호출
var instance = new foo(); // instance

// 4. apply/call/bind 호출
var bar = { name: 'bar' };
foo.call(bar);   // bar
foo.apply(bar);  // bar
foo.bind(bar)(); // bar

 

 

함수호출📢

전역객체는 모든 객체의 유일한 최상위 객체를 의미함.

Browser-side 에서는 window 객체를 ,

Server-side에서는 global 객체를 의미함.

 

전역객체는 전역스코프(Global Scope)를 갖는 전역변수(Global variable)를 프로퍼티로 가진다.

글로벌 영역에서 선언한 함수는 전역객체의 프로퍼티로 접근할 수 있는 전역변수의 메소드이다..

 

말이 쥰내 생소하고 어렵긴한데 그림으로 보면 그리 어렵지 않다.

 

var ga = 'Global variable';

console.log(ga); // Global variable
console.log(window.ga); // Global variable

function foo() {
  console.log('invoked!');
}
window.foo(); // invoked

 

기본적으로 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(); // bar의 this는 전역객체에 바인딩.
  }
};

obj.foo();

 

콜백함수의 경우에도 this 는 전역객체에 바인딩 된다.

 

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

내부함수의 this가 전역객체를 참조하는 것을 회피하려면 that을 사용하면 된다.

 

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    var that = this;  // Workaround : this === obj

    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

      console.log("bar's that: ",  that); // obj
      console.log("bar's that.value: ", that.value); // 100
    }
    bar();
  }
};

obj.foo();

 

참조 : 모던 자바스크립트 Deep dive

위 방법 이외에도 JS는 this를 명시적으로 바인딩 할 수 있는 apply, call, bind 메서드를 제공한다.

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(a, b) {
      console.log("bar's this: ",  this); // obj
      console.log("bar's this.value: ", this.value); // 100
      console.log("bar's arguments: ", arguments);
    }
    bar.apply(obj, [1, 2]);
    bar.call(obj, 1, 2);
    bar.bind(obj)(1, 2);
  }
};

obj.foo();

 

다음 글은 메서드 호출!