[JS] what's 'this'?

chooing·2022년 5월 15일
0

JavaScript

목록 보기
3/3

this?

  • this는 자신을 호출한(속한) 객체를 나타내는 자기 참조 변수이다.
  • this는 함수가 만들어질 때가 아닌 실행될 때(런타임될 때) 그 값이 결정된다.
  • this는 함수가 실행될 때 함수를 호출하고 있는(소유하고 있는) 객체를 참조한다.

일반 함수

스크립트 내에서 호출

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

one(); // window

위와 같은 경우 one()는 호출되고 있는 객체가 따로 없으므로 전역 객체인window를 참조한다.

엄격모드로 호출

"use strict"

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

one(); // undefined

엄격모드에서 실행하면 one()라는 함수를 직접 호출하게되어 해당 함수가 어디에 소유되고 있는지 알 수 없으므로 undefined이다.

함수를 중복한다면?

function one(){
  console.log(this);
  
  function two(){
    console.log(this);
  }
   two(); // window
}
one(); // window

함수를 중복해도 결국은 다른 객체를 참조하고 있는게 아니기 때문에 결과는 window 가 나온다.

일반 함수의 호출은 다 window인가?

아니다. mapforEachthis의 값을 따로 지정해 줄 수 있다. 그렇기 때문에 무조건 일반 함수가 전역 객체인 window를 참조한다고 단정지을 수는 없다.

forEach(콜백함수, this 값)
map(콜백함수, this값)

const birds = ['🦆','🐓','🦜'];

birds.forEach(function(bird){console.log(this)},{'종류':'조류'});
// {'종류':'조류'}
// {'종류':'조류'}
// {'종류':'조류'}

birds.forEach(function(bird){console.log(this.종류, bird)},{'종류':'조류'});
//조류 🦆
//조류 🐓
//조류 🦜

birds.map(function(bird){console.log(this)},{'종류':'조류'});
// {'종류':'조류'}
// {'종류':'조류'}
// {'종류':'조류'}
// [undefined, undefined, undefined]

매서드 호출

this를 통해 자신이 속한 객체 참조 (자신을 호출한 객체 참조)가 가능하므로 메서드 내부의 this를 통해 객체에 접근할 수 있다.

function sayFood(){
	console.log(`${this.food}${this.price}원입니다.`);
}

const 도시락 ={
	food:'🍱',
  	price: 4000,
    introduce: sayFood
}

const 푸딩 ={
	food:'🍮',
  	price: 1200,
    introduce: sayFood
}

푸딩.introduce(); //🍮는 1200원입니다.
도시락.introduce(); //🍱는 4000원입니다.
const 주문서 = [{
    '가게이름': '노노치킨',
    '위치': '넘버투타워 3층',
    '주문금액': 50000,
    '할인금액': 15000,
    '결재금액':function(){return this.주문금액 - this.할인금액},
  },{
    '가게이름': '미세스피자',
    '위치': '대왕빌딩 1층',
    '주문금액': 35000,
    '할인금액': 20000,
    '결재금액':function(){return this.주문금액 - this.할인금액},
}];

console.log(`${주문서[0].가게이름}에서 결재하실 금액은 ${주문서[0].결재금액()}원입니다.`);
// 노노치킨에서 결재하실 금액은 35000원입니다.

console.log(`${주문서[1].가게이름}에서 결재하실 금액은 ${주문서[1].결재금액()}원입니다.`);
// 미세스피자에서 결재하실 금액은 15000원입니다.

this를 내맘대로 조종하기

만약에 this로 참조하고 싶은 내용이 달라진다면 어떻게 해야할까? 그럴때 사용하는 것이 apply() call() bind()이다. 이 함수의 메소드를 사용하여 this가 참조하는 객체를 원하는 대로 직접 지정해 줄 수 있다.

call()

함수.call(this가 참조할 객체, 값...)

const 저녁식사 = {
  mainMenu : '찜닭',
  sayMenu: function(source){ 
    console.log(`오늘의 저녁은 ${source} ${this.mainMenu}입니다~!`);
 }
};

const 다이어트 ={
  mainMenu: '닭가슴살',
};

저녁식사.sayMenu('로제'); // 오늘의 저녁은 로제 찜닭입니다~!
저녁식사.sayMenu.call(다이어트,'로제'); // 오늘의 저녁은 로제 닭가슴살입니다~!

apply()

함수.apply(this가 참조할 객체, 배열...)

const 점심식사 = {
  mainMenu : '돈까스',
  sideMenu : '고로케',
  sayMenu: function(extra1, extra2){ 
    console.log(`오늘의 점심은 ${extra1} ${this.mainMenu}${extra2} ${this.sideMenu}입니다~!`);
 }
};

const 다이어트 ={
  mainMenu: '샐러드',
  sideMenu: '닭가슴살',
};

점심식사.sayMenu('고구마','치즈'); 
// 오늘의 점심은 고구마 돈까스와 치즈 고로케입니다~!

점심식사.sayMenu.apply(다이어트,['고구마','치즈']); 
// 오늘의 점심은 고구마 샐러드와 치즈 닭가슴살입니다~!

call()과 apply() 둘 다 인수에 지정 값을 넣는 것은 동일하지만,
call()과 다르게 apply()는 배열의 값을 받을 수 있다.

bind()

함수.bind(this 객체)
앞서 두 메소드와 다르게 bind()를 사용하면 this가 고정된 새로운 함수를 만들어낸다.

function sayMenu(){
    console.log(`오늘 아침은 ${this.mainMenu}입니다.`);
}
const 다이어트 ={
	mainMenu:'단백질 쉐이크',
  	todayMenu: sayMenu
};

const 아침식사 ={
	mainMenu:'맥모닝',
  	todayMenu: sayMenu
};

다이어트.todayMenu(); // 오늘 아침은 단백질 쉐이크입니다.
아침식사.todayMenu(); // 오늘 아침은 맥모닝입니다.

아침식사 불러올 때를 '단백질 쉐이크'가 나오게 하고 싶다면?

function sayMenu(){
    console.log(`오늘 아침은 ${this.mainMenu}입니다.`);
}
const 다이어트 ={
	mainMenu:'단백질 쉐이크',
  	todayMenu: sayMenu
};

const 아침식사 ={
	mainMenu:'맥모닝',
  	todayMenu: sayMenu.bind(다이어트)
};

다이어트.todayMenu(); // 오늘 아침은 단백질 쉐이크입니다.
아침식사.todayMenu(); // 오늘 아침은 단백질 쉐이크입니다.

이런식으로 하면 아침식사.todayMenu()를 했을때 단백질 쉐이크가 나온다. 여기서 아침식사 객체 안에 bind()를 넣어주는 이유는 bind()의 반환 값이 함수이기 때문이다. 앞서 call() apply()처럼 객체의 메소드에 bind()를 붙여보면 알 수 있다.

function sayMenu(){
    console.log(`오늘 아침은 ${this.mainMenu}입니다.`);
}
const 다이어트 ={
	mainMenu:'단백질 쉐이크',
  	todayMenu: sayMenu
};
const 아침다이어트 = sayMenu.bind(다이어트);

아침다이어트(); // 오늘 아침은 단백질 쉐이크입니다.

화살표 함수

앞서 함수들은 동적으로 this가 결정되었지만, 화살표 함수를 사용하면 상위 스코프의 this로 고정된다.(Lexical this)

const 누구세요 ={
  myName: '홍길동',
  myAge: 7,
  sayName(){
  	console.log(this);
  	console.log(`나는 ${this.myAge}${this.myName}이다.`);
	let saysayName = () =>{
      console.log(this);
      console.log(`나는 ${this.myAge}${this.myName}이다.`);    
      let saysaysayName = () =>{
        console.log(this);
        console.log(`나는 ${this.myAge}${this.myName}이다.`);          	
      }
      saysaysayName();
    }
    saysayName();
  }
}
누구세요.sayName();
// {myName: '홍길동', myAge: 7, sayName: ƒ}
// 나는 7살 홍길동이다.

// {myName: '홍길동', myAge: 7, sayName: ƒ}
// 나는 7살 홍길동이다.

// {myName: '홍길동', myAge: 7, sayName: ƒ}
// 나는 7살 홍길동이다.

생성자 함수

앞서 this는 나를 호출한(속한) 객체를 참조했지만 생성자 함수에서는 this가 생성자가 만들어낸 객체 즉, 인스턴스를 참조한다.

function TeddyBear(clothes){
  this.clothes = clothes;
  this.makeBear = function(){
  	console.log(`${this.clothes}를(을) 입은 테디 베어`);
  }
} 

const dressBear = new TeddyBear('드레스');
dressBear.makeBear(); // 드레스를(을) 입은 테디 베어

위의 예시에서 thisTeddyBear를 참조하는 것이 아닌 TeddyBear로 만들어낸 dressBear를 참조하고 있다. 여기서 TeddyBear는 생성자 함수이며 dressBear는 생성자 함수로 만든 인스턴스 객체이다.

profile
멋찐 프론트엔드 개발자가 되기 위해 공부 중입니다

0개의 댓글