[JS] this

세나정·2023년 6월 5일
0

this는 기본적으로 window (console에 찍어보면 나옴)
strict 모드라면 undefined

js : window
node : global

이제는 두 개 모두 globalThis로 합쳐짐

this는 함수가 호출 될 때 결정 된다.

예시

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)이 나옴

화살표 함수는 무조건 전역을 가리키는 것이 아닌 부모 스코프를 가리킴 (스코프는 호출이 아닌 선언)

bind, call, apply

function sayName() {
	console.log(this.name)
}

라는 코드가 있다면 함수의 this를 조작하는 것

sayName.bind( { name : 'Hong' }) () // Hong

bind는 새로운 함수를 만들고 호출은 따로 해줘야함

sayName.call( { name : 'Hong' }) // Hong

sayName.apply( { name : 'Hong' }) // Hong

그래서 렉시컬 스코프처럼 적었을 때 결정되는 것이 아니라
This는 함수를 호출할 때 정해진다.

함수의 종류 따른 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을 가리키게 됨

결론

this는 호출 될 때 결정되므로 함수의 겉만 봤을 떄는 알 수 없는 게 정답

예를 들어 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) 이렇게 바꿔 주어야함

this를 분석할 수 없는 경우

이렇게 공지사항이란 곳에 addEventListener를 추가해서 클릭할 때마다 this를 출력해봄

우리가 배운대로라면 window가 나와야할테지만 <h3~~~> 이 나오는 걸 볼 수 있다.

이러한 이유는 addEventListener가 호출될 때 그 함수가 어떻게 호출되는지 알 수 없기 때문에 우리가 분석할 수 없음 (이럴 땐 외워야됨)

(하지만, 공식문서의 답으로는 this가 header라고는 나와있다.)

함수가 일급객체다? : 함수자체를 값으로 전달할 수 있다는 것

누군가 이 코드의 this를 물어본다면
"this는 분석할 수 없는 게 맞고 공식문서에서 나온 것은 addEventListener의 this는 header입니다." 라고 하면 됨 (공식문서 보기 전에는 모른다.)

화살표 함수를 넣는순간 this는 당연히 window를 가리키게 됨 (부모니까, 이런 걸 렉시컬 this)

하지만 선언과 호출을 구분해야함

그저 적기만 한다고 되는 것이 아니라 우리는 addEventListener라고 "호출" 을 했기 떄문

*참고로 addEventListener는 C++로 만들어짐

bind : bind는 this만 바꾼 새로운 함수를 만드는 것

apply : 바꾼 후 호출까지 해주는 애

a.apply(window) === a.bind(window)() === a.call(window) 셋이 같은 말
어플라이는 매개변수는 배열로 넣어줌 ("a"pply니까 "a"rray)

제로초님의 공식
이렇게 Call Stack (호출 스택), 선언 Map을 그리는 것

이 공식으로 되지 않는 것은 안티패턴 (쓰면 안 되는 패턴)이기 때문에 안 쓰면 됨

profile
압도적인 인풋을 넣는다면 불가능한 것은 없다. 🔥

0개의 댓글