this는 기본적으로 window (console에 찍어보면 나옴)
strict 모드라면 undefined
js : window
node : global
이제는 두 개 모두 globalThis로 합쳐짐
예시
const obj = {
name : 'hong',
sayName() {
console.log(this.name)
}
};
obj.sayName() // hong
이지만
const sayN = obj.sayName;
sayN()을 하면 // ' '
window.name인 공백이 나옴
함수가 호출 될 때 This에다가 특별한 동작을 안 했으면 window
함수 앞에 객체가 붙는다면 This는 그 객체를 가리킴
const obj = {
name : 'hong',
sayName : () => {
console.log(this.name)
}
};
는 this를 가리키지 않음 (this가 변경되지 않음)
즉, 공백 (window.name)이 나옴
화살표 함수는 무조건 전역을 가리키는 것이 아닌 부모 스코프를 가리킴 (스코프는 호출이 아닌 선언)
function sayName() {
console.log(this.name)
}
라는 코드가 있다면 함수의 this를 조작하는 것
sayName.bind( { name : 'Hong' }) () // Hong
bind는 새로운 함수를 만들고 호출은 따로 해줘야함
sayName.call( { name : 'Hong' }) // Hong
sayName.apply( { name : 'Hong' }) // Hong
그래서 렉시컬 스코프처럼 적었을 때 결정되는 것이 아니라
This는 함수를 호출할 때 정해진다.
const obj = {
name : 'hong',
sayName() {
console.log(this.name);
function inner() {
console.log(this.name);
}
inner();
}
}
obj.sayName()
// hong
// ' '
만약 여기서 inner를 화살표 함수로 바꾼다면?
const obj = {
name : 'hong',
sayName() {
console.log(this.name);
inner = () => {
console.log(this.name);
}
inner();
}
}
obj.sayName()
// hong
// hong
아래에 존재하는 this.name이 obj.name을 가리키는 것을 볼 수 있음
화살표 함수는 부모함수의 this를 그대로 사용하기 때문
그렇기 때문에 결론적으로, 둘 다 hong을 가리키게 됨
예를 들어 const sayN = obj.sayName; 이라면은 다시 또 window를 가리키니까
sayN() 처럼 함수로 호출하면 window를 가리킬 수 밖에 없음
하지만 obj.sayName처럼 객체에 지정해서 한다면 그 객체를 가리키게 되는 것
즉, inner처럼 화살표 함수라서 this가 부모를 가리키므로 sayName만을 보는 게 아니라, sayName이 어떻게 호출 되느냐를 봐야함
잘 보면 sayName의 this값을 inner (화살표 함수니까) 그대로 받아오는 것을 볼 수 있음
하지만 이렇게 inner가 화살표 함수가 아니라 선언형 함수라면 화살표 함수처럼 부모의 것을 받아오는 것이 아니라 window를 가리키게 됨 (window.name은 빈칸)
그래서 선언형 함수인데 this를 바꾸고 싶다면
call, bind, apply를 사용하여
함수 호출 부분에 inner.call(obj) 이렇게 바꿔 주어야함
이렇게 공지사항이란 곳에 addEventListener를 추가해서 클릭할 때마다 this를 출력해봄
우리가 배운대로라면 window가 나와야할테지만 <h3~~~> 이 나오는 걸 볼 수 있다.
이러한 이유는 addEventListener가 호출될 때 그 함수가 어떻게 호출되는지 알 수 없기 때문에 우리가 분석할 수 없음 (이럴 땐 외워야됨)
(하지만, 공식문서의 답으로는 this가 header라고는 나와있다.)
함수가 일급객체다? : 함수자체를 값으로 전달할 수 있다는 것
누군가 이 코드의 this를 물어본다면
"this는 분석할 수 없는 게 맞고 공식문서에서 나온 것은 addEventListener의 this는 header입니다." 라고 하면 됨 (공식문서 보기 전에는 모른다.)
화살표 함수를 넣는순간 this는 당연히 window를 가리키게 됨 (부모니까, 이런 걸 렉시컬 this)
그저 적기만 한다고 되는 것이 아니라 우리는 addEventListener라고 "호출" 을 했기 떄문
*참고로 addEventListener는 C++로 만들어짐
a.apply(window) === a.bind(window)() === a.call(window) 셋이 같은 말
어플라이는 매개변수는 배열로 넣어줌 ("a"pply니까 "a"rray)
제로초님의 공식
이렇게 Call Stack (호출 스택), 선언 Map을 그리는 것
이 공식으로 되지 않는 것은 안티패턴 (쓰면 안 되는 패턴)이기 때문에 안 쓰면 됨