this에 대해서 상기하기 위해 다시 되짚어보자면,
실행컨텍스트는 실행할 코드에 제공할 환경정보들을 모아놓은 객체이고, 이 객체에 담겨있는 내용은 크게 세개인데 각각 1.VE, 2.LE, 3.ThisBinding이다.
그리고 this는 메서드로 호출될 때는 자연스럽게 호출의 주체가 되는 객체에 귀속이 되지만, 일반적인 함수로 호출되었을 때는 호출의 주체를 알 수 없기 때문에 자연스럽게 전역 객체를 바라보게 된다.
그리고 이러한 방식이 인간인 개발자의 시선에서 문맥상 납득이 되지 않을 때가 있기 때문에 이를 임의적으로 변경하여 Binding해주는 방법이 있다.
.call()이나 .apply()같은 메서드를 사용하거나 콜백함수에서 this로 binding할 객체를 명시적으로 나타내는 방법등이 있다. 두가지가 정말로 되는지 확인하기 위해서 예시를 시행해보는 도중 문제가 생겼다.
<script>
var func = function () {
console.log(this);
};
func.call({x : 1});
//>> {x : 1}
</script>
이 경우에는 원하는대로 잘 수행이 되었다. 그런데
첫번째 문제)
<script>
var func = function (x) {
console.log(this,x);
};
func.call({x:1});
func(1)
</script>
func.call({x:1});
은 생각대로 this가 잘 binding되었지만, func(1)
은 다시 전역객체를 보여주었다.
이유는 첫번째, func.call({x:1});
가 func라는 함수가 앞으로 바라볼 this를 변경하는 '동작'으로 착각했다는 것이었다. 저 함수가 실행되면 그 아래로는 모두 적용되어 func라는 함수가 실행될 때마다 {x : 1}이라는 객체에 binding될 줄 알았지만 .call()함수는 그런 역할을 하지 않는다.
그렇다면 이런건 어떨까?
<script>
func(1).call({x : 1})
</script>
이러면 func(1)이 실행될 때도 this가 {x : 1}에 binding되지 않을까라고 생각했지만 현실은 "TypeError: Cannot read properties of undefined (reading 'call')
라는 에러문구였다. undefined의 속성을 읽을 수 없다는 것인데 곰곰이 생각해보면 당연하다. func라는 함수인 객체에 메서드로써 실행되었어야 할 .call()이 func(1)이라는 함수 '실행결과값'의 프로퍼티를 읽으려는 시도로 보였다는 것이다.
그리고 두번째 사실을 재확인하기 위해서 forEach() 함수에도 적용을 해보았다. forEach()는 첫번째 매개변수로 콜백함수를 받고, 두번째 매개변수로 binding할 객체를 받게 된다. 그래서 다음과 같이 시도하였다.
<script>
arr1 = [10, 20, 30];
arr1.forEach(
() => {
console.log(this);
},
arr1
);
</script>
이러면 this에 arr1이 binding되지 않겠냐는 것인데 결과는 자꾸 전역변수가 binding된 것으로 나왔다. 그리고 고민을 반복하다 매니저님께 여쭤보았는데. 결론은 역시 기본이었다.
보란듯이 개발블로그에 썼던 내용인데
forEach와 같은 함수는 첫번째 매개변수로 콜백함수를 받는다. 그리고 콜백함수의 자리에는 어떤 함수도 들어갈 수 있다. 사실 그 이상의 의미도, 그 이하의 의미도 없다. 그렇지만 가장 전형적으로 예시를 드는 .forEach(()=>{})
라는 형태에 매몰된 나머지 화살표 함수만이 forEach함수의 매개변수로 쓰인다고 은연중에 생각했던 것 같다.
그리고 this binding의 기본적인 법칙을 망각했던 것 또한 원인이었다고 할 수 있겠다.