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
인가?아니다. map
과 forEach
는 this
의 값을 따로 지정해 줄 수 있다. 그렇기 때문에 무조건 일반 함수가 전역 객체인 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
로 참조하고 싶은 내용이 달라진다면 어떻게 해야할까? 그럴때 사용하는 것이 apply()
call()
bind()
이다. 이 함수의 메소드를 사용하여 this
가 참조하는 객체를 원하는 대로 직접 지정해 줄 수 있다.
함수.call(this가 참조할 객체, 값...)
const 저녁식사 = {
mainMenu : '찜닭',
sayMenu: function(source){
console.log(`오늘의 저녁은 ${source} ${this.mainMenu}입니다~!`);
}
};
const 다이어트 ={
mainMenu: '닭가슴살',
};
저녁식사.sayMenu('로제'); // 오늘의 저녁은 로제 찜닭입니다~!
저녁식사.sayMenu.call(다이어트,'로제'); // 오늘의 저녁은 로제 닭가슴살입니다~!
함수.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(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(); // 드레스를(을) 입은 테디 베어
위의 예시에서 this
는 TeddyBear
를 참조하는 것이 아닌 TeddyBear
로 만들어낸 dressBear
를 참조하고 있다. 여기서 TeddyBear
는 생성자 함수이며 dressBear
는 생성자 함수로 만든 인스턴스 객체이다.