this

Happhee·2022년 3월 11일
0

 💜 JavaScript 💜

목록 보기
5/19
post-thumbnail

자바스크립트에서 this는 자바와 달리 this에 바인딩되는 객체의 종류가 한 가지가 아니며, 해당 객체는 함수 호출 방식에 따라 달라지는 특성(동적)을 가지고 있다.

✅ 여기서 바인딩이란, 식별자와 값을 연결하는 과정을 의미한다.
예를 들면, 변수 선언은 변수 이름(식별자)과 확보된 메모리 공간의 주소를 바인딩하는 것이다.
때문에 this 바인딩은 this(키워드로 분류되지만, 식별자의 역할을 수행)와 this가 가리킬 객체를 바인딩하는 것을 말한다.

this에 대해 자세하게 알아보자.


this

this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다

따라서 this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티메서드를 참조할 수 있다.


함수 호출 방식

this 바인딩은 함수 호출 방식에 따라 동적으로 결정되는 특성을 가지고 있다.

함수 호출 방식은 아래와 같다.

  • 일반 함수 호출
  • 메서드 호출
  • 생성자 함수 호출
  • Function.prototype.apply / call / bind 호출

일반 함수 호출

기본적으로 this에는 전역 객체가 바인딩된다.

브라우저 콘솔을 켜고, this를 콘솔로 출력해보면

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

window가 반환되는 것을 알 수 있다.

객체 메서드 안으로 this를 넣어보면,

let obj = {
  a : function(){
    console.log(this);
  },
};
obj.a();	// a가 반환

obj.a( )로 호출할 때의 this는 a를 가리키므로 window가 반환되지 않는다.
만약, window를 this로 받고 싶다면, 객체 메서드를 window에서 호출하면 된다.

let b = obj.a;
b( );	// window{ }

b에 객체 메소드 할당하면 더 이상 obj의 메소드 아니다.
따라서 이에 대한 호출을 실행하면 window에 this가 바인딩 된다.

일반 함수에서 this === window이기에 this.name, this,age는 각각 window.name, window.age로 나타낼 수 있다.

var name = "seohee";

console.log(name);
console.log(window.name);

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

모두 다 똑같은 값을 출력하는 것을 확인할 수 있다.


내부 함수 호출

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

  • 메소드의 내부함수일 경우에도 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();
  }
};

obj.foo();

window에서 obj.foo( )를 호출하였기에 foo의 this에는 obj가 바인딩되지만,
bar는 foo의 내부 함수이므로 전역 객체가 바인딩되는 결과를 보였다.

  • 심지어 콜백함수도 전역객체에 바인딩된다.
var value = 1;

var obj = {
  value: 100,
  foo: function() {
    setTimeout(function() {
      console.log("callback's this: ",  this);  // window
      console.log("callback's this.value: ",  this.value); // 1
    }, 100);
  }
};

obj.foo();

window 객체가 바인딩됨을 알 수 있다.

이를 회피하기 위한 방식으로 that이나 apply, call, bind 메소드를 사용하기도 한다.

  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);
  }

메소드 호출

함수가 객체의 프로퍼티 값이면 메소드로서 호출된다.

이때, 메소드 내부의 this는 해당 메소드를 소유한 객체
즉, 해당 메소드를 호출한 객체에 바인딩된다.

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

var obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName();	
obj2.sayName();

obj1.sayName( )의 this는 obj1이므로 Lee가 출력되고,
obj2.sayName( )의 this는 obj2이므로 Kim이 출력된다.


생성자 함수 호출

자바스크립트의 생성자 함수는 말 그대로 객체를 생성하는 역할을 한다.
자바와 달리, 기존 함수에 new 연산자를 붙여 호출하면, 해당 함수는 생성자 함수처럼 동작할 수 있다.

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

var me = new Person('Lee');
console.log(me); 

var you = Person('Kim');
console.log(you); 

me는 생성자 함수를 사용하였지만, you는 생성자 함수로 호출하지 않았으므로 동작하지 않는다.


apply / call / bind 호출

계속해서 말해왔듯이 this에 바인딩될 객체는 함수 호출 패턴에 의해 결정된다. 이는 자바스크립트 엔진이 수행하는 것이며, 암묵적 this 바인딩 외에 특정 객체에 명시적으로 바인딩하는 방법인 Function.prototype.apply,call, bind메소드가 제공된다.

이들을 호출하는 주체는 함수이기에 각 메소드들이 this를 특정 객체에 바인딩할 뿐, 본질적인 기능은 함수 호출이라는 점을 기억해야 한다.

예제 코드를 보자

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

var foo = {};

// apply 메소드는 생성자함수 Person을 호출한다. 이때 this에 객체 foo를 바인딩한다.
Person.apply(foo, ['name']);

console.log(foo); // { name: 'name' }

📚 학습할 때, 참고한 자료 📚

profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

0개의 댓글