말 그대로 이것!!
우리가 글을 읽거나 말을 할때 쓰는 그거 이거는 문맥으로 파악해야 제대로 이해하고 사용할 수 있다. 자바스크립트의 this도 마찬가지다.
this는 부른 놈 누구???!!!를 살펴보면 된다. 부른 놈은 당연히 실행된 함수를 봐야 알 수 있다.
따라서, this를 알기 위해서는 반드시 함수 실행문을 봐야한다. 그래야 누가 불렀는지 잘 알 수 있기 때문이다.
this를 구분할 수 있는 함수 실행 조건은 다음과 같다.
<script>
const name = 'Juliana';
function printName() {
console.log(this.name);
}
printName();
/**
*일반 함수 실행
*this는 global Object
*window.name = 'Juliana' 이므로 출력값은 Juliana
*/
</script>
.
앞에 오는 객체가 this가 된다.
예시1 냉장고에는 무슨 음식이 있을까?
<script>
const fridge = {
inneritem: "cheesecake",
food: function () {
console.log(this.inneritem);
},
};
fridge.food();
/**
* Dot Notation 실행
* this =fridge
* fridge.food() = function(){console.log(fridge.inneritem)};
* 출력값은 cheesecake
*/
</script>
<script>
//위의 내용 동일
// vs 일반 함수 호출
const doWeHaveSth = fridge.food;
doWeHaveSth();//일반 함수 실행 -> this는 {} 따라서 undefined
</script>
예시2-1 소희랑 민우는 롤코를 탈 수 있을까?
롤러코스터 규정상 키가 140이 넘어야 탈 수 있다(verifyRide 참고)
<script>
const height = 180;
function verifyRide() {
return this.height > 140;
}
const sohee = {
name: "sohee",
height: 140,
verifyRide: verifyRide,
};
const minwoo = {
name: "minwoo",
height: 150,
verifyRide: verifyRide,
};
const rollercoaster = {
canRide: (rider) => {
if (!rider.verifyRide) {
return console.log("Can't ride!");
}
return console.log("Go Ride!");
},
};
rollercoaster.canRide(sohee);
rollercoaster.canRide(minwoo);
</script>
놀랍게도 여기서는 소희와 민우 보다 Go Ride가 된다.
소희는 140이 안넘는데도 탈 수 있다고 한다....(위험해!!)
예시 2-2 소희랑 민우는 롤코를 탈 수 있을까?
<script>
const height = 180;
function verifyRide() {
return this.height > 140;
}
const sohee = {
name: "sohee",
height: 140,
verifyRide: verifyRide,
};
const minwoo = {
name: "minwoo",
height: 150,
verifyRide: verifyRide,
};
const rollercoaster = {
rider: (rider) => {
if (!rider.verifyRide()) {
return console.log("Can't Ride!");
}
return console.log("Go Ride!");
},
};
rollercoaster.rider(sohee);
rollercoaster.rider(minwoo);
</script>
이 코드에선 소희는 탈 수 없고 민우만 탈 수 있다.
소희는 왜 두 코드에서 다른 결과가 나온 걸까??
소희 객체가 가지고 있는 verifyRide는 verifyRide 일반함수를 가리킨다.
verifyRide 함수는 this가 global scope를 가리키고, global scope의 height는 180으로 verifyRide 함수이 반환값이 true가 된다. 따라서 Go Ride!가 출력된다.
<script>
const height = 180;
function verifyRide() {
return this.height > 140;
}
const sohee = {
name: "sohee",
height: 140,
verifyRide: verifyRide,
};
const rollercoaster = {
canRide: (rider) => { // rider = {name: "sohee", height: 140, verify: function}
if (!rider.verifyRide) {
//sohee.verifyRide = function verifyRide, 즉 일반함수 실행
//function verifyRide 내의 this는 global scope가 되고 this.height = 180이 된다
// 180 > 140 이고 반환값이 true가 되어 if 조건을 만족하지 않는다.
return console.log("Can't Ride!");
}
return console.log("Go Ride!");//반환값
},
};
rollercoaster.rider(sohee);//Go Ride!
</script>
소희 객체의 verifyRide는 여전히 function verifyRide를 가리킨다.
하지만 이번엔 rollercoaster의 조건이 sohee.verifyRide(), 즉 소희 객체 내의 메소드가 아니라, dot notation 실행값이 false일 때를 말한다.
즉, sohee.verifyRide()라는 dot nation 함수를 호출하기 때문에 return 값이 sohee.height > 140으로 되고, false이기 때문에 "Can't Ride!"가 출력된다.
<script>
const height = 180;
function verifyRide() {
return this.height > 140;
}
const sohee = {
name: "sohee",
height: 140,
verifyRide: verifyRide,
};
const rollercoaster = {
rider: (rider) => {
if (!rider.verifyRide()) {
//sohee.verifyRide() = return 140>140 false 반환
return console.log("Can't Ride!");//조건 충족
}
return console.log("Go Ride!");
},
};
rollercoaster.rider(sohee);//Can't Ride!
</script>
한 끗 차이로 이렇게 결과가 달라질 수 있으니 this를 쓸 때는 항상 유의해야한다.
이거 3개로 실행되는 함수는 괄호 안에 있는 것이 this로 지정된다.
위 3개는 this 바인딩 함수라고 한다.
자바스크립트는 실행하는 함수에 따라 this가 바뀔 수 있는데 this를 고정시키고 싶을 때 쓸 수 있는 것이 바로 this 바인딩 함수이다.
첫번째 파라미터로 오는 것을 this로 지정하여 함수를 실행할 수 있다.
<script>
const letsCook = {
menu: function(){
return this.howCooked + "" + this.ingredients
}
}
const recipe1 = {
howCooked: "fried",
ingredients: "eggs"
}
const recipe2 = {
howcooked : "grilled",
ingredients: "meat"
}
letsCook.menu.call(recipe1);//this = recipe1, 출력값은 fried eggs
letsCook.menu.call(recipe2);//this = recipe2, 출력값은 grilled meat
</script>
두번째부터 오는 파라미터는 실행하는 함수의 파라미터로 전달된다.
(두번째 파라미터부터는 갯수 상관없이 넣을 수 있다)
<script>
function multiply(a,b,c){
}
const myFruit = {
name: 'Apple';
}
multiplay(myFruit, 1, 2, 3);
//Apple
//6
</script>
파라미터는 총 2개를 받는다.
첫번째 파라미터는 call 처럼 this로 지정된다.
두번째 파라미터는 반드시 배열이어야 한다.
두번째 파라미터의 요소들은 실행하는 함수의 파라미터로 전달된다.
<script>
function multiply(a, b, c) {
console.log(this.name);
console.log(a * b * c);
}
const myFruit = {
name: "Apple",
};
multiply.apply(myFruit, [1, 2, 3]);
//Apple
//6
검색을 하다보니 apply는 prototype과 같이 쓸 일이 많은 것 같다.
나중에 prototype을 배우고 나면 함께 활용하는 법도 같이 정리해야 할 것 같다.
괄호 안에 있는 객체를 this로 지정하여 새로운 함수를 반환한다.
반환만 되고 실행이 되지 않는다는 점에서 call, apply와 다르다.
<script>
function leftIceCream() {
return this.name + ": " + this.num + "개 남았습니다.";
}
const icecream1 = {
name: "수박바",
num: 3,
};
const icecream2 = {
name: "더위사냥",
num: 5,
};
const countIceCream = leftIceCream.bind(icecream1);
//icecream1이라는 객체에 leftIceCream이라는 함수 메서드를 대입해 icecream1.leftIceCream을 만든 것과 같은 효과
//물론 새로운 함수를 만들어 반환하기 때문에 실제로 icecream1에 leftIceCream 메소드가 들어가지 않는다.
//따라서 countIceCream = 새로운 만들어낸 icecream1.leftIceCream을 넣은 효과가 됨
console.log(countIceCream());
//countIceCream을 실행한다는 것은 새로 만들어낸 icecream1.leftIceCream()하는 것과 같으므로
//dot notation 실행 경우에 해당하므로 this는 icecream1이 된다.
//따라서 icecream1.name + ": " + icecream1.num + "개 남았습니다" 가 출력된다.
//출력값은 수박바: 3개 남았습니다.
</script>
bind는 this를 지정하고 새로운 함수를 반환만 하고 실행만 하지 않는다.
이는 call과 비교해보면 확실히 알 수 있다.
위의 예제를 bind와 call을 사용하여 다시 비교해보자.
<script>
//bind 사용 시
console.log(leftIceCream.bind(icecream1));
//반환값은 ƒ leftIceCream() {
// return this.name + ": " + this.num + "개 남았습니다.";
//} 즉, 함수가 반환되는 것이지 실행이 되지는 않는다.
console.log(leftIceCream.bind(icecream1)());
//수박바: 3개 남았습니다.
//반드시 실행은 따로 해주어야 실행이 된다.
</script>
<script>
//call 사용 시
console.log(leftIceCream.call(icecream1))
//수박바: 3개 남았습니다.
</script>
new와 함께 함수를 사용할 경우 이 함수를 생성자 함수라고 한다.
새로운 빈 객체를 반환하기 때문이다.
이 new로 만들어진 객체의 this는 새로운 객체를 생성했을 때 대입했던 것이 된다.
말로 적으니 정말 설명하기 어려운 것 같다...
<script>
function IceCream(name, price) {
this.name = name;
this.price = price;
}
const 메로나 = new IceCream("메로나", 500);//새로운 객체 생성
console.log(IceCream("설레임", 1000));//일반 함수이므로 this.name, this.price 모두 undefined
console.log(메로나);//IceCream {name: "메로나", price: 500}
</script>
https://velog.io/@devmin/TIL-%ED%95%A8%EC%88%98-%EB%A9%94%EC%86%8C%EB%93%9C-5ok29tthyz
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-Call-Bind-Apply
https://dmitripavlutin.com/javascript-this-interview-questions/
https://dev.to/liaowow/take-this-quiz-understand-how-this-works-in-javascript-44dj