자바스크립트에서 this란?

Jayden ·2023년 3월 14일
0

1. this 키워드

this 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencing variable)이다. this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.

this는 자바스크립트 엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조할 수 있다. 함수를 호출하면 arguments 객체와 this가 암묵적으로 함수 내부에 전달된다. 함수 내부에서 arguments 객체를 지역 변수처럼 사용할 수 있는 것처럼 this도 지역변수 처럼 사용할 수 있다. 단. this가 가리키는 값, this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

cf) this 바인딩

바인딩이란, 식별자와 값을 연결하는 과정의 의미한다. 예를 들어, 변수 선언은 변수 이름(식별자)과 확보된 메모리 공간의 주소를 바인딩 하는 것이다. this 바인딩은 this와 this를 가리킬 객체를 바인딩하는 것이다.

// 객체 리터럴

const circle = {
  radius : 5,
  getDiameter(){
   	return 2* this.radius; 
  }
};

console.log(circle.getDiameter());
//생성자 함수
function Circle(radius){
 this.radius = radius 
}

Circle.prototype.getDiameter = function(){
  
  return 2 * this.radius;
};


//인스턴스 생성
const circle = new Circle(5);
console.log(circle.getDiameter()); //10

자바나, C++ 같은 클래스 기반 언에서 this는 언제나 클래스가 생성하는 인스턴스를 가리키지만, 자바스크립트의 this는 함수가 호출되는 방식에 따라 this에 바인딩 될값, 즉 this 바인딩이 동적으로 결정된다. 또한 strict mode(엄격 모드) 역시 this 바인딩에 영향을 준다.

this는 코드 어디에서든 참조 가능하다. 전역에서도 함수 내부에서도 참조할 수 있다.

//this는 어디서든지 참조 가능한다.
// 전역에서 this는 전역 객체 window를 가리킨다.
console.log(this);

function square(number){
 console.log(this);
 return number * number;
}

square(2);

const person = {
 	name : 'Lee'
    getName() {
     	// 메서드 내부에서 this는 메서드를 호출한 객체를 가리킨다. 
    	console.log(this);
      	return this.name;
    }
};

console.log(person.getName()); //Lee

function Person(name) {
 	this.name = name;
  	// 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 가리킨다. 
  	console.log(this); //Person {name : "Lee"}
}

const me = new Person('Lee');

2. 함수 호출 방식과 this 바인딩

함수의 상위 스코프를 결정하는 방식인 렉시컬 스코프는 함수 정의가 평가되어 함수 객체가 생성되는 시점에 상위 스코프를 결정하지만, this 바인딩은 함수 호출 시점에 결정된다.

//this 바인딩은 함수 호출 방식에 의해서 결정된다.
const foo = function () {
 console.dir(this) 
}

//동일한 함수도 다양한 방식으로 호출될 수 있다.

//1. 일반 함수 호출
//foo 함수를 일반적인 방식으로 호출
//this는 전역 객체, window를 가리킨다.
foo(); //window

//2. 메서드 호출
//foo 함수를 객체의 프로퍼티로 할당 후 호출
//foo 함수 내부의 this는 메서드를 호출한 객체 obj를 가리킨다.
const obj = {foo};
obj.foo();

//3. 생성자 함수 호출
//foo 함수를 new 연산자와 함께 생성자 함수를 호출
//foo 함수 내부의 this는 생성자 함수가 생성한 인스턴스를 가리킨다.
new foo();

//4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출
//foo 함수 내부의 this는 인수에 의해 결정된다.

const bar = {name : 'bar'};

foo.call(bar);
foo.apply(bar);
foo.bind(bar);

(1) 일반 함수 호출

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

	function foo(){
     	console.log("foo's this : " , this); // window
 		function bar(){
         	console.log("bar's this : ",  this); //window 
        }
      bar();
    }
foo();

위의 예제처럼 전역 함수, 중첩 함수를 일반 함수로 호출하면 함수 내부 this에는 전역 객체 window가 바인딩 된다.

strict mode가 적용된 일반 함수 내부에 this는 undefined가 바인딩 된다.

function foo(){
 'use strict';
  
  console.log("foo's this : ", this); //undefined
  function bar(){
   	console.log("bar's this : ", this); //undefined
  }
  bar();
}
foo();

메서드 내에서 정의한 중첩 함수도 일반 함수로 호출 되면 중첩 함수 내부에서 this에는 전역 객체가 바인딩된다.

//var 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티이다.
//const 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티가 아니다.
//const value = 1;
var value = 1;

const obj = {
  value : 100,
  foo(){
   console.log("foo's this :", this);
   console.log("foo's this.value : ", this.value);
    
    //메서드 내에서 정의한 중첩 함수
   	function(){
        console.log("bar's this : ", this);
      	console.log("bar's this.value : ", this.value);                         
    }
    
    bar();
    
  }
};

obj.foo();

콜백 함수가 일반 함수로 호출된다면 콜백 함수 내부의 this에도 전역 객체가 바인딩된다. 어떤 함수라도 일반 함수로 호출되면 this에 전역 객체가 바인딩 된다.


var value = 1;

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

obj.foo()

메서드 내부의 중첩 함수나 콜백 함수의 this 바인딩을 메서드의 this 바인딩과 일치시키기 위한 방법은 다음과 같다.

var value = 1;

const obj = {
  value : 100,
  foo() {
    // this 바인딩(obj)을 변수 that에 할당한다.
   const that = this;
    
   setTimeOut(function(){
     console.log(that.value);
   }, 100);
  }
};

obj.foo();

화살표 함수를 사용해서 this 바인딩을 일치시킬 수도 있다.

var value = 1;

const obj = {
 value : 100,
  
 foo() {
  //화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다.
  setTimeout(()=> console.log(this.value), 100); 
 }
};

(2) 메서드 호출

메서드 내부의 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다.


const person = {
  name : 'Lee',
  getName() {
   	//메서드 내부에 this는 메서드를 호출한 객체에 바인딩
    return this.name;
  }
};

// 메서드 getName()을 호출한 객체는 Person이다.
console.log(person.getName());

(출처) 모던 자바스크립트 Deep Dive

profile
J-SONE 프론트엔드 개발자

0개의 댓글