JS | TIL | 화살표 함수의 this, 배열 메서드 push()

Autumn·2020년 12월 21일
0

TIL

목록 보기
4/19
post-thumbnail

화살표 함수의 this

var obj = {
  outer: function() {
    console.log(this);
  },
  outer2: () => {
  	console.log(this);
  }
  
  obj.outer(); // this는 obj
  obj.outer2(); // this는 전역객체 (window)

outer 는 일반 함수고 outer2 는 화살표 함수다. obj.outer(); 는 객체의 메서드로 실행된 것이기 때문에 this 는 함수를 호출한 객체 obj 가 된다. 그런데 화살표 함수로 작성했을 때 궁금한 점이 두 가지 있었다. 화살표 함수에 this 가 없다는 건 알고 있었다. 그리고 머릿속에는 this === 호출한 놈 !!!!!! 이라는 생각이 깊게 자리 잡고 있었다.

  1. outer2 를 호출한 놈이 obj 니까 thisobj 여야 하는 것 아닌가?
  2. 1번이 틀렸다 하더라도, 스코프 체인에서 제일 가까운 걸 찾으면 그래도 obj 아닌가?

이야기를 나누다보니,

  1. console.log() 가 전역객체의 메서드이기 때문에 전역객체가 호출한 거라서 this는 전역객체다. (setTimeout처럼...)

라는 의견도 나왔다.
알고 보니 실행컨텍스트와 this 를 제대로 이해하지 못해서 생긴 오해(?)였다. (어제 공부한건데.. 😂)

우선, 실행컨텍스트는 보통 함수가 호출될 때 생성된다고 생각하면 된다. 함수가 호출되는 순간 실행컨텍스트가 생성이 되면서 3가지 일을 한다.

  1. VariableEnvironment 수집
  2. LexicalEnvironment 수집
  3. ThisBinding

1과 2에서는 각각 세부적으로 보면, environmentRecord (자신의 스코프에 있는 식별자 수집, 호이스팅과 같다고 생각하면 됨), outerEnvironmentReference (내 바로 바깥에 있는 스코프의 식별자 정보, 즉 콜스택에서 지금꺼 바로 아래에 있는 놈!!) 두 가지 정보를 수집한다.

다시 말하면, this 바인딩은 보통의 경우 함수가 호출될 때 일어나는 것이다. 그럼 다시 예제를 보면, obj.outer2(); 부분의 콜스택은 전역컨텍스트가 맨 아래에 있고 그 바로 위에 outer2 실행컨텍스트가 있는 모양새이다. outer2 실행컨텍스트가 생겼을 때 화살표함수이므로 this가 아예 outer2에는 존재하지 않기 때문에, 가장 가까운 스코프에서부터 찾아나가는데 그게 바로 전역객체 window 였던 것이다. (node.js 에서는 또 약간 다르게 나오는데 어쨌든 전역객체 맞음!)

⭐️ 스코프 체인이 코드상에서 무조건 바깥 블럭이 아니라, 실행컨텍스트 맥락에서 생각해야 한다는 큰 깨달음을 얻었다. ⭐️
물론 그 바로 바깥 블럭이 함수라면.. 그렇게 찾아도 되겠지만 위 예제처럼 오브젝트라면 주의할 필요가 있겠다. !!!


2021.01.16 내용 추가

위에서 '가장 가까운 스코프에서부터 찾아나가는데 그게 바로 전역객체 window 였던 것이다.' 라고 써놨는데 저걸 쓸 때는 그냥 받아들였었나보다. ㅋㅋㅋ 다시 의문점이 생겼는데, 객체 리터럴의 중괄호 {}는 스코프를 생성하지 않는가? 가 궁금해졌다.

찾아본 결과 block (MDN 바로가기) 이라는 것은 statement일 때를 뜻하는 것이었다. 객체 리터럴은 '값'으로 평가되는 expression이기 때문에 block에 해당하지 않는다. 따라서 위 예제의 obj.outer2(); 에서는 this binding이 없는 화살표 함수이므로 함수가 선언된 위치를 기준으로 this를 탐색하는데, obj 객체를 탐색하는 것이 아니라 곧바로 전역에서 this를 탐색하는 것이다. 객체 변수를 var로 정의하든 const, let으로 정의하든 마찬가지이다. 객체 리터럴은 block이 아니다! statement가 아니기 때문!!



배열 메서드 push

newArr 에 할당 후 push 하는것과 [...arr].push(2) 를 바로 하는 것의 결과가 다르게 나와서 대체 이게 뭘까 궁금했다. 원인은 정말 간단했는데 push 메서드의 반환값이 바로 push 완료된 배열의 길이였던 것이었다!!!!!!!!

push 정말 자주 쓰던 메서드였는데 이걸 이제야 알다니... 참고로 자매품 unshift 또한 배열의 길이를 반환한다. 이 사실을 알아내고 MDN을 보니 너무나 친절하게 바로 첫 줄에 쓰여 있었다. ㅋㅋㅋㅋㅋㅋㅋ 스터디를 하다보니 그동안 보고 싶은 것만 골라서 봐왔다는 걸 가슴 깊이 깨달았다. 매일매일 새로 배우는 게 많아서 재미있다. 😊

profile
한 발짝씩 나아가는 중 〰 🍁 / 자잘한 기록은 아래 🏠 아이콘에 연결된 노션 페이지에 남기고 있어요 😎

0개의 댓글