javascript-logo.png

this

function plus(number) {
  console.log(this);

  return number * number;
}
plus(2);

> Window
  • 자바스크립트의 this는 함수가 호출될 때 암묵적으로 전달 받는다.
  • 함수 호출 방식에 따라 this에 바인딩되는 객체가 달라진다.

1. 함수 호출

var global = "im global";

console.log(global);
console.log(window.global);

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

window.a();

> im global
> im global
> Window
  • 전역 객체는 모든 객체의 최상위 객체를 의미하고 this는 기본적으로 전역 객체 window에 바인딩된다. 따라서, 전역으로 선언한 함수는 전역 객체의 메소드이다.
  • 글로벌 영역에 변수, 함수를 선언하고 호출하면 전역 객체에 접근 가능한 변수 window를 사용하여 호출한 것과 같다.

1-1. 내부함수

function a() {
  console.log("a this", this);

  function b() {
    console.log("b this: ", this);
  }

  b();
}
a();

> a this: Window
> b this: Window

1-2. 메소드 내부의 함수

var value = 1;

var obj = {
  value: 100,
  a: function() {
    console.log("a this: ", this);
    console.log("a value: ", this.value);

    function b() {
      console.log("b this: ", this);
      console.log("b value: ", this.value);
    }

    b();
  }
};

obj.a();

> a this: obj
> a this: 100
> b this: Window
> b this: 1

1-3. 콜백함수

var value = 1;

var obj = {
  value: 100,
  a: function() {
    setTimeout(function() {
      console.log("this: ",  this);
      console.log("value: ",  this.value);
    }, 100);
  }
};

obj.a();

> this: Window
> value: 1

내부함수, 메소드 내부의 함수, 콜백함수의 this도 기본적으로 전역 객체에 바인딩되기 때문에

window를 참조한다.

2. 메소드 호출

var animal = {
  name: 'Candy',
  sayName: function() {
    console.log(this.name);
  }
}

var flower = {
  name: 'Jasmin'
}

flower.sayName = animal.sayName; // 메소드 주입

animal.sayName();
flower.sayName();

> Candy
> Jasmin
  • 객체의 프로퍼티 값이 함수이면 메소드로 호출된다.
  • 이 때 메소드 내부의 this는 메소드를 소유한 객체에 바인딩된다.
  • 메소드를 호출하는 각각의 객체를 기준으로 name 프로퍼티로 출력된다.

3. 생성자 함수 호출

function Animal(name) {
  this.name = name;
}

var myPuppy = new Animal('Candy'); // 생성자 함수 호출

console.log(myPuppy.name);

> Candy
  • 생성자 함수로 함수를 호출했을 때는, 함수 호출과 메소드 호출과는 this의 바인딩이 다르다.
  • 생성자 함수는 new 라는 키워드를 사용해서 호출하고 빈 객체 생성과 this 바인딩을 진행한다.

따라서, this는 생성자 함수가 생성한 객체에 바인딩된다.

❓그럼 명시적으로 this에 객체를 바인딩해서 유연하게 this를 사용할 수는 없을까?

apply/call/bind 함수를 사용하여 this에 객체를 바인딩 시킬 수 있다.

3-1. apply

var animal = function (name) {
  this.name = name;
};

var a = {};
animal.apply(a, ['Candy']);

console.log(a);

> { name: 'Candy' }
  • 함수명.apply(thisArg, [argsArray]) 의 문법으로 사용한다.
  • apply 메소드를 통하여 this에 객체를 바인딩하고, 아규먼트를 통하여 프로퍼티에 값을 할당한다.

3-2. call

numberFunc.apply(a, [1, 2, 3]);

numberFunc.call(a, 1, 2, 3);
  • call 메소드는 apply 메소드와 기능이 동일하다. 차이점은 배열로 넘기던 인자를 각각 하나의 인자로 넘긴다는 것이다.

3-3. bind

var animal = {
  name: 'Candy',
  sayName : function() {
    setTimeout(function() {
      console.log("이름은 " + this.name + " 입니다");
    }, 500);
  }
};

animal.sayName();

> 이름은 undefined 입니다.

위의 코드는 결과값이 의도한대로 올바르게 출력되지 않는다.
메소드 내부의 함수는 this에 전역 객체를 바인딩 하기 때문이다.
이러한 경우에 bind 메소드를 사용하면 this에 animal 객체를 바인딩 시킬 수 있다.

var animal = {
  name: 'Candy',
  sayName : function() {
    setTimeout(function() {
      console.log("이름은 " + this.name + " 입니다");
    }.bind(this), 500);
  }
};

animal.sayName();

> 이름은 Candy 입니다.
  • bind 메소드는 인자로 전달한 this가 새로운 함수를 리턴한다.

bind는 함수를 선언할 때 this를 지정하고, apply/call은 함수를 호출할 때 this를 지정한다.

❓화살표 함수에서는 this의 스코프가 다르다던데?

화살표 함수의 가장 큰 특징이다.
함수 호출에 따라 this에 바인딩할 객체가 동적으로 결정되는 일반 함수와 달리, 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다.
화살표 함수 정리 글


📂 참고자료

  • 모던 자바스크립트 Deep Dive 도서