[Javascript] this (실행 컨텍스트)

Hyejin·2023년 3월 23일
0

Javascript

목록 보기
3/4
post-thumbnail

What is this in Javascript?

In most cases, the value of this is determined by how a function is called (runtime binding).

  • 함수가 호출될 때 this의 값이 결정
  1. 그냥 쓰이거나 일반함수 안에서 쓰이면 this는 window를 뜻함
    window는 모든 전역변수, 함수, DOM을 보관하고 관리하는 전역객체

  2. strict mode에서, 함수 안에서 쓰이는 thisundefined이다.

  3. Object 자료형 내에 함수들이 있을 수 있는데, 거기서의 this값은 this를 포함하고 있는 객체 자체를 뜻함 ✅
    아래 코드의 cat이라는 객체가 가진 메소드 getName 안에 있는 this는, cat을 뜻한다.

  4. 이벤트리스너 안에서, thise.currentTarget과 동일

<button id="button">버튼</button>
document.querySelector('#button').addEventListener('click', function(e){
	console.log(this)
  	console.log(e.currentTarget)
  	// 둘 다 버튼 태그를 출력함
  	// e.currentTarget은 이벤트리스너가 붙은 객체(=지금 이벤트가 동작하는 곳을)를 말한다.
})

참고. (ES6) Arrow function에서 , this값을 함수 밖에 있던 window객체를 그대로 쓴다는 특징이 있음.

const cat ={
  name: 'yaong',
  age: 1,
  getName: function(){
  	console.log("cat getName", this)
  }
}
cat.getName() //cat getName {name: 'yaong', age: 1, getName: ƒ}

그런데,

const cat ={
  name: 'yaong',
  age: 1,
  getName: function(){
  	console.log("cat getName", this)
  }
}
//cat.getName()

const globalCat = cat.getName;
globalCat(); //Window {window: Window, self: Window, document: document, name: '', location: Location, …}
  • window 객체가 반환됨

WHY?

/*
	차이점: 
    해당객체를 참조하여 접근연산자(.)를 통한 함수호출
    vs.
    전역에서(외부로부터) 함수 호출
*/
cat.getName(); // A.b

globalCat(); //b

그렇다면,

const cat ={
  name: 'Yaong',
  age: 1,
  getName: function(){
  	console.log("cat getName", this)
  }
}
//cat.getName() // A.b

const globalCat = cat.getName;
globalCat(); // b

const cat2 = {
  name: 'Dundun',
  age: 1,
  getName: cat.getName
}
cat2.getName() //cat getName {name: 'Dundun', age: 1, getName: ƒ}

알 수 있는 점 :
호출하는 객체에 따라 this가 달라진다.

<button id='button'>this는 누굴까?</button>
const btn = document.getElementById('button');
btn.addEventListener('click', cat.getName);
// <button id='btn'>this는 누굴까?</button>
  • 즉, this는 함수가 호출될 때 결정이 되는데, 함수를 호출한 객체는 btn 이므로 <button>가 출력된다.

this를 고정하고 싶다면, bind(객체변수명) 이용

const bindGetname = cat2.getName.bind(cat);
bindGetname();
//cat getName {name: 'Yaong', age: 1, getName: ƒ}

const btn = document.getElementById('button');
btn.addEventListener('click', cat.getName.bind(cat));
//cat getName {name: 'Yaong', age: 1, getName: ƒ}
  • this가 고정되어 첫번째 Cat의 이름을 가져온다.

thisarrow function(화살표 함수)

//innerFunc은 함수안의 함수(내부함수)
//내부 함수가 호출될 때 this값은 어떻게 달라지는가?
const cat3 = {
	name: 'Titi',
  	getName: function(){
    	console.log('getname', this.name);
      	const innerFunc = function(){
        	console.log('innerFunc', this.name);
        }
        innerFunc();
    }
}
cat3.getName()

//getname Titi >> 예측한대로, 결과값 출력. this == cat3
//innerFunc undefined >> 결과값이 없음. this == Window 객체

WHY?

innerFunc() 도 마찬가지로, 누가 호출했는지 알 수 없으므로,

  • getName함수 안에 내부함수로 존재한다 하더라도, innerFunc() 자체는 window객체를 호출한다.

응용 1.

getName의 this와 innerFunc의 this같은 값으로 만들려면?

(1) bind()을 사용해도 되고,
(2) innerFunc을 arrow function(화살표함수)로 바꾼다.

const cat3 = {
	name: 'Titi',
  	getName: function(){
    	console.log('getname', this.name);
      	const innerFunc = () => { //🔥🔥🔥
        	console.log('innerFunc', this.name);
        }
        innerFunc();
    }
}
cat3.getName()

//getname Titi
//innerFunc Titi

알 수 있는 점 :
화살표 함수에서 this는, 화살표 함수가 속해있는 곳의 상위 this를 상속받는다.

  • (자바스크립트에서 this는) 일반함수에서의 this와 화살표함수에서의 this가 다름
  • 일반함수에서 this는 함수 호출한 객체에 의해 값이 결정된다면,
  • 화살표함수에서 this는, 함수가 속한 곳의 상위 this를 상속받는다.

따라서, 화살표함수가 있던 함수(innerFunc)의 상위함수(getName)의 this(= cat3)를 상속받게 되고, 결과적으로 innerFunct의 this와 getName의 this가 같게 된다.

응용 2.

const ageTest = {
  unit: '세',
  ageList : [10, 20, 30],
  getAgeList : function(){
    const result = this.ageList.map(function(age){
    	return age;
    })
    console.log(result);
  }
}
ageTest.getAgeList(); //[10, 20, 30]
const ageTest = {
  unit: '세',
  ageList : [10, 20, 30],
  getAgeList : function(){
    const result = this.ageList.map(function(age){
    	return age + this.unit; //이렇게 출력하고 싶다면?
    })
    console.log(result);
  }
}
ageTest.getAgeList(); //[NaN, NaN, NaN] 👻👻👻

WHY?

  • 왜 NaN가 출력되었나?

  • result함수의 return되는 thisWindow 객체이다.

  • 따라서, this.unit == undefined 이고,

  • (숫자 + undefined == NaN 이므로) age + this.unit == NaN 이 출력되는 것이다.

  • 이를 해결하려면, this가 포함된 함수를 일반함수가 아닌 화살표 함수(()=>{})로 바꾼다.

const ageTest = {
  unit: '세',
  ageList : [10, 20, 30],
  getAgeList : function(){
    const result = this.ageList.map(age => { // 🔥🔥🔥
    	return age + this.unit; //이렇게 출력하고 싶다면?
    })
    console.log(result);
  }
}
ageTest.getAgeList(); //['10세', '20세', '30세']

위의 코드과 같이, 화살표 함수에서 this는, 화살표 함수가 속해있는 곳의 상위 this를 상속받는다. 즉, this가 포함된 result함수의 상위this(=ageTest)를 상속받아 제대로 출력하게 된다.

(참고) 화살표 함수는 bind() 제공 ❌

마지막으로,

this를 쓰고 싶을 때 일반함수를 쓸까, 화살표함수를 쓸까??

  • 일반적으로, this를 쓰고 싶다면 일반함수를 써라

    • bind()로 원하는 객체를 지정해 줄 수 있기 때문
    • 예측 가능한 this로 만들 수 있음
  • 하지만 내부함수의 경우 this가 포함되었다면, 화살표 함수를 써라

    • 상위 함수의 this를 상속받기 때문
    • 함수 안에 있는 함수의 경우, 같은 this를 쓴다면 화살표 함수

Reference:
(MDN) this
자바스크립트 this / 코딩알려주는누나(Youtube)

0개의 댓글