'this' in javascript

kwakjihoon·2025년 1월 29일
post-thumbnail

this란?

일반적으로 this는 자신을 가리키는 참조변수를 의미한다. this 자체가 객체 자신에 대한 참조 값을 가지고 있다는 뜻이다. 자바스크립트에서는 독특하게 함수가 어떻게 호출 되었느냐에 따라서 this가 가리키는 대상이 달라진다.

웹 브라우저에서 this가 사용될 때는 전역 객체와 Window 객체를 가지게 되는데, 객체의 메소드를 정의 하기 위한 함수 안에서는 메서드를 호출한 객체를 가리키게 된다.

console.log(this); //window 객체 정보 로깅

보통 this는 함수 안에서 자주 사용하게 되는데 아래의 예시를 살펴보자.

const user = {
	firstName: 'kwak',
  	lastName: 'jihoon',
  	getFullName: function() {
    	return `${user.fisrtName} ${user.lastName}`;
    },
};

console.log(user.getFullName());

해당 함수는 user 객체를 이용해서 전체 이름을 반환하는 함수다. 이 기능을 추가 활용하기 위해서 함수를 분리한다면 어떻게 될까?

function getFullName() {
	return `${user.fisrtName} ${user.lastName}`; 
}

const user = {
	firstName: 'kwak',
  	lastName: 'jihoon',
  	getFullName: getFullName,
};

const admin = {
	firstName: 'kwak_admin',
  	lastName: 'jihoon_admin',
  	getFullName: getFullName,
};

console.log(user.getFullName());
console.log(admin.getFullName());

//output: kwak jihoon
//		  kwak jihoon

하나의 함수에서 각각의 객체로 접근하여 새로운 정보를 입력하고 싶지만, getFullName 함수가 user 객체를 가리키고 있기 때문에, admin으로 접근을 해도 user 객체에 대한 정보가 호출이 된다.

function getFullName() {
	return `${this.fisrtName} ${this.lastName}`;  //this로 변경
}

const user = {
	firstName: 'kwak',
  	lastName: 'jihoon',
  	getFullName: getFullName,
};

const admin = {
	firstName: 'kwak_admin',
  	lastName: 'jihoon_admin',
  	getFullName: getFullName,
};

console.log(user.getFullName());
console.log(admin.getFullName());

//output: kwak jihoon
//		  kwak_admin jihoon_admin

getFullName의 함수 객체를 this로 바꾸면 user와 admin 객체 모두 잘 작동하는 것을 볼 수 있다. 위에서도 말했듯이 this는 함수를 호출한 객체를 가리키는 키워드다. 코드를 작성할 때 값이 미리 결정되는 게 아니라 함수가 호출될 때 어떤 객체가 그 함수를 호출했는지에 따라서 상대적으로 값이 변하게 된다.

✍️ Summary

  • 특정 객체를 가리키지 않는 this: window 객체에 대한 정보
  • 특정 객체를 가리키는 this: 가리키는 객체에 대한 정보

함수 호출 방식에 따른 this 바인딩

MDN에선 this에 대해 아래와 같이 정의하고 있다.

... 대부분의 경우 this의 값은 함수를 호출한 방법에 의해 결정됩니다. 실행중에는 할당으로 설정할 수 없고 함수를 호출할 때 마다 다를 수 있습니다. (생략) ES2015는 스스로의 this 바인딩을 제공하지 않는 화살표 함수를 추가했습니다(이는 렉시컬 컨텍스트안의 this값을 유지합니다).

this는 함수 호출 방식에 따라 바인딩할 객체가 동적으로 결정된다.

함수 호출

기본적으로 this는 전역 객체에 바인딩 된다. 그렇기에 아래의 함수들은 외부 함수가 아닌 전역 객체에 바인딩 된다.

  • 일반 전역 함수
  • 내부 함수
  • 콜백 함수
function one() {
  console.log("one: ",  this);  // window 객체 바인딩(전역)
  function two() {
    console.log("two: ", this); // 내부 함수도 window 객체 바인딩(전역)
  }
  two();
}
one();

메소드 호출

함수가 객체를 인자값으로 호출하면, this는 호출되는 메소드 객체 정보를 가리키게 된다. 즉, 해당 메소드를 호출한 객체에 바인딩 된다.

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

var lastname = {
  name: 'jihoon'
}

lastname.sayName = fisrtname.sayName;

fisrtname.sayName(); // kwak
lastname.sayName(); // jihoon

call()

function introduce(job, age) {
    console.log(`I'm ${this.name}. I'm a ${job} and I'm ${age} years old.`);
}

const person = { name: "jihoon" };

// `this`를 `person`으로 설정하고 추가적인 인자를 넘겨 실행
introduce.call(person, "developer", 26);
// I'm jihoon. I'm a developer and I'm 26 years old.
  • this를 명확하게 지정할 수 있고, 함수가 즉시 실행한다.
  • 추가적인 인자를 개별적으로 전달 한다.

apply()

function introduce(job, age) {
    console.log(`I'm ${this.name}. I'm a ${job} and I'm ${age} years old.`);
}

const person = { name: "jihoon" };

// `this`를 `person`으로 설정하고 인자를 배열로 넘겨 실행
introduce.apply(person, ["developer", 26]);
// I'm jihoon. I'm a developer and I'm 26 years old.
  • call() 메서드와 동일하게 동작하지만, 인자를 배열로 전달해야 한다.
  • 일반적으로 배열에 대한 정보를 그대로 인자로 넘겨야 할 때 사용한다.

bind()

function introduce(job, age) {
    console.log(`I'm ${this.name}. I'm a ${job} and I'm ${age} years old.`);
}

const person = { name: "jihoon" };

// `this`를 `person`으로 설정한 새로운 함수 생성
const boundIntroduce = introduce.bind(person, "developer");

// `boundIntroduce` 실행 (age 인자를 추가 전달)
boundIntroduce(26);
// I'm jihoon. I'm a developer and I'm 26 years old.
  • 별도의 새로운 함수로 반환하기에, 함수가 즉시 실행되지 않는다.
  • 인자를 부분 설정 할 수 있다.
  • 이벤트 핸들러에서 this가 undefined 또는 window가 되는 문제를 해결할 때 사용한다.
const user = {
    name: "jihoon",
    greet() {
        console.log(`I'm ${this.name}`);
    }
};

// `setTimeout`에서 `this` 문제 발생
setTimeout(user.greet, 1000); // I'm undefined

// `bind()`를 사용하여 `this`를 유지
setTimeout(user.greet.bind(user), 1000); // I'm David
  • call()this를 변경하고 함수를 즉시 실행해야 할 때.
  • apply()this를 변경하고, 인자를 배열 형태로 넘겨야 할 때.
  • bind()this를 변경하되, 함수를 나중에 실행하고 싶을 때.

🤔Arrow function?

Arrow function의 경우 this 바인딩이 특정 객체를 가리키는 것이 아닌 window 객체 정보를 가지게 된다.

const obj = {
  name: "My Object",
  
  arrowFunc: () => {
    console.log("Arrow Function this: ", this); // `window` 또는 `globalThis`
  },

  normalFunc: function() {
    console.log("Normal Function this: ", this); // `obj`를 가리킴
  }
};

// 실행
obj.arrowFunc();  // this → window (전역 객체)
obj.normalFunc(); // this → obj (정상적으로 객체를 가리킴)

Arrow function 문법에서 this를 사용해야 한다면 일반 함수 문법으로 코드를 바꿔줘야 한다.

profile
딥다이브 습관화 하기 ☺️

0개의 댓글