-
[JavaScript] "Illegal invocation" errors개발/Javascript 2022. 5. 31. 03:14
"Illegal invocation" 오류는 함수 호출과 관련해서 발생합니다.
JavaScript에서 this는 상황에 따라 달라지는데,
호출되는 함수가 동작 과정에서 this를 참조하고 있을 때
this가 참조하는 객체가 달라지면 문제가 됩니다.
다음 예제를 살펴봅시다.
const $ = document.querySelector; $("#root"); // TypeError
언뜻 보면 문제가 없을 것 같지만, 살펴봅시다.
document 객체의 메소드의 this는 document 객체를 가리킵니다.
document 객체의 메소드에서 다른 메소드나 객체에 접근할 때 this가 필요합니다.
만약 this가 가리키는 객체가 document가 아니게 된다면 동작을 제대로 수행할 수 없기 때문에
오류를 발생시키는 게 맞습니다.
document.querySelector("#root")로 사용할 때는 this가 document를 참조하지만
메소드 객체를 $으로 가져와 $()로 호출하면
$()의 this는 호출자인, 상위 객체인 window가 되는 것입니다.
이 예제에서는 window지만 상황에 따라 this는 다른 객체가 될 수 있습니다.
정상 작동을 하기 위해서는 querySelector가 실행될 때의 this가 document라고 지정하면 됩니다.
const $ = document.querySelector.bind(document); $("#root"); // OK
예제 하나만 더 살펴보겠습니다.
bind 메소드를 이용해 this를 묶어놓은 채로
새로운 객체로 받을 수 있고
bind 없이 받은 뒤에
apply, call 함수를 이용해 this를 지정하면서 호출할 수도 있습니다.
const obj = { func: function() { console.log("Calling func() 'this' refers to ", this); if (this !== obj) { throw new TypeError("Illegal invocation❌"); } console.log("Successfully called obj.func()✅"); } } obj.func(); // OK. 'this' refers to obj const {func} = obj; // func.apply(obj); func(); // TypeError. 'this' refers to Window
다음과 같은 경우도 생각해볼 수 있습니다.
두 코드 모두 동일한 동작을 합니다.
node.children.map(callback).forEach(element.doSomething.bind(element)); node.children.map(callback).forEach((elem) => element.doSomething(elem));
'개발 > Javascript' 카테고리의 다른 글
[JavaScript]중복 제거(feat. Set의 한계) (0) 2022.06.21 [VScode] 익스텐션으로 Prettier 설정하기 (0) 2022.05.31 Response.json() (0) 2022.05.06 reduce를 이용해 배열 객체를 하나의 객체로 만들기 (0) 2022.04.26 키보드 입력 (0) 2022.03.30