[Front-end] 개발자 공부

[개발 공부 24일차] Closure, Execution Context와 Scope

MOLLY_ 2024. 1. 26. 07:15
728x90

 

이해하기 어려운 노답 3형제

 
 
챌린지 반 세션이 끝나고 할 일 하다가 이제서야 쓰는 TIL이다.. 일단 조금 피곤한 관계로 눈이 반쯤 풀려있는 상태다. 상태?.. 하루 종일 코딩 공부를 하다 보니 '상태'처럼 배운 내용 관련 단어나 표현만 보이면 바로 코딩 용어가 떠올라버린다. 방금도 '상태'라고 하면서 '헉.. state..?' 이러고 있는 나를 발견할 수 있었다. 아무튼,,, 오늘은 뭘 배웠는지 써보자.
 
공부하며 내가 생각하기에 기억해야 할 내용과 중요한 부분만 작성하며 정리해보려고 한다. 노답 삼형제는 특히, 좀 더 쉽게 접근하고  이해하기 위해 나만의 언어로 표현하며 작성해 보았다.
 
 

< 목차 >

1. [React 숙련] 핵심 정리

   1) React.memo

   2) Virtual DOM

2. 이해하기 난해한 노답 삼형제

   1) Execution Context (실행 컨텍스트)

   2) Closure(클로저)

   3) Scope(스코프)

3. 금일 소감

 
 
위 목차를 적으면서도.. '뭐야... 오늘 안 자기로 한 거야?'라고 자문하게 되는 구성이다. 하... 모르면 공부해야죠. 물론 지금 시각 01:33이다.. 하.... 고민하지 말고 바로 가.
 
 

1. [React 숙련] 핵심 정리
   1) React.memo

: re-rendering 방지템 중 하나로, React.memo를 이용해서 컴포넌트를 메모리에 저장해두고 필요할 때 갖다 씀!
⇒ memo를 사용하면 부모 컴포넌트의 state 변경으로 인해 props 변경이 일어나지 않는 한, re-rendering 되지 않는다.
   = component memoization
 
▼  예문

export default React.memo(Box3);

 
 

* 함께 알아두면 좋은 개념!
캐싱(cashing)
: 메모리에 임시 저장
⇒ 맨 처음 해당 값 반환 시, 특별한 곳(메모리)에 저장해서 필요할 때마다 이미 저장한 값 불러와서 사용 (매번 함수를 호출하지 않아도 됨)

조건부 Rendering은 아래 링크에서 참조!
https://react.dev/reference/react/memo#specifying-a-custom-comparison-function

 

   2) Virtual DOM(가상 DOM)

: HTML 태그를 JS에서 이용할 수 있는 객체로 만든 것  ⇒  HTML 문서의 '객체 기반 표현 방식'
실제 DOM과 구조가 완벽히 동일한 '복사본' 형태
[왜 사용?] 실제 DOM을 조작하는 것보다 '메모리'상에 올라와 있는 JavaScript 객체를 변경하는 작업이 훨씬 더 가볍기 때문
 

DOM Tree

 
Virtual DOM에 대해 더 자세히 알기 전에 일단, DOM이란 뭘까?

  • 웹 페이지 = document(문서)
  • 웹 페이지를 이루는 component = element(엘리먼트)

⇒ DOM은 엘리먼트를 tree 형태로 표현한 것
 
 

 
Virtual DOM을 사용하면 여러 DOM을 한 번에 묶어서 조작할 수 있어서 좋다.
 

< React가 항상 갖고 있는 2가지 버전의 Virtual DOM >
① 화면 갱신 : 구조가 담겨 있는 가상 DOM 객체
② 화면 갱신 : 보여야 할 가상 DOM  객체
 

Virtual DOM과 Browser DOM의 차이

 
 
지금까지는 Virtual DOM의 장점 위주로 알아봤다. 그렇다면 단점으로는 어떤 게 있을까? 단점도 알아보자.
 

Even with shouldComponentUpdate, updating your entire app's virtual DOM in one go is a lot of work. A while back, the React team introduced something called React Fiber which allows the update to be broken into smaller chunks. This means (among other things) that updates don't block the main thread for long periods of time, though it doesn't reduce the total amount of work or the time an update takes.

shouldComponentUpdate를 사용하더라도 전체 앱의 가상 DOM을 한 번에 업데이트하는 것은 많은 작업이 필요합니다. 얼마 전, React 팀은 업데이트를 더 작은 덩어리로 나눌 수 있는 React Fiber라는 것을 도입했습니다. 이는 무엇보다도 업데이트가 오랜 시간 동안 메인 스레드를 차단하지 않는다는 것을 의미하지만, 총 작업량이나 업데이트에 걸리는 시간을 줄이지는 못합니다.

- Virtual DOM is pure overhead 中

 
 
1. 추가적인 메모리 사용
: Virtual DOM메모리상에 DOM과 완전히 동일한 구조의 메모리를 유지하게 되는데, 따라서 추가적인 메모리를 사용하게 된다.

2. 복잡성 증가
: 개발자가 애플리케이션의 뷰(View)와 상태(State)를 동기화하기 위해 추가적인 추상화 계층을 사용해야 한다. 이로 인해 애플리케이션의 복잡성이 증가할 수 있다.

3. 특정 상황에서의 불필요함
: 모든 상황에 완벽하게 적합하지 않을 수 있다. 정말 간단한 UI나 작은 규모의 애플리케이션에서는 불필요한 overhead일 수 있다.

 
 
 
* [참고] API: 프로그램을 조작할 수 있는 인터페이스

[Reference]
1) https://www.codestates.com/blog/content/dom-javascript
2) https://svelte.dev/blog/virtual-dom-is-pure-overhead
3) https://velog.io/@dongjun187/React-Virtual-DOM-%EA%B8%B0%EC%B4%88-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC
 
 
 

2. 이해하기 난해한 노답 삼형제

JavaScript Engine

   1) Execution Context (실행 컨텍스트)

: 실행 가능한 자바스크립트의 코드 블록

특정한 코드를 실행하기 위해 코드를 일종의 블록으로 나눔!
⇒ 그 코드 블록에 들어가있는 변수, 함수, this, arguments 등에 대한 정보를 담고 있는 하나의 환경
 
Execution Context는 자바스크립트 엔진의 Call Stack이라는 곳에 차곡차곡 쌓이게 된다.
동일한 환경에 있는 코드들을 실행할 때 필요한 환경정보를 모아 컨텍스트를 구성하고, 이를 콜 스택에 쌓아놓은 뒤, 가장 위에 있는 컨텍스트와 관련 있는 코드들을 실행하는 것으로 코드의 환경과 순서를 보장한다.
 
하나의 실행 컨텍스트를 구성할 수 있는 방법으로는 다음과 같다.

  • 전역 공간
  • eval() 함수
  • 함수

 

실행되는 순서

 
 
흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것!
어떤 실행 컨텍스트가 활성화될 때, 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드에서 실행하는 데 필요한 환경 정보들을 수집해서 '실행 컨텍스트 객체'에 저장한다.
 
 

실행 컨텍스트의 구조

 
 
실행 컨텍스트 객체는 활성화되는 시점에 VariableEnvironment, LexicalEnviornment, ThisBinding 3가지 정보를 수집한다.
VariableEnvironment와 LexicalEnvironment는 environmentRecord(매개변수명, 식별자, 함수명 등 수집)와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference로 구성된다.
 
실행 컨텍스트를 생성할 때,
VariableEnvironment는 초기 상태 유지, LexicalEnvironment는 실행 도중 변경사항이 즉시 반영된다.
 
 
 
더불어, 아래의 기초 개념을 알면 Execution Context를 더 잘 이해할 수 있다.
어떻게 알았냐고?.. 나도 알고 싶지 않았다..
 
이해하려고 읽는 중에 계속 모르는 개념이 등장해서 이해가 되려다가도 "어? lexical 개념 모르죠? ㅋㅋ",  "어? 이번엔 parsing이 뭔지 제대로 모르죠? ㅋㅋ" 하는 것 같다. 후.. 어차피 아래 개념을 확실하게 알고 있지 않으면 설명을 봐도 무슨 말인지 이해가 잘 안 된다.
 
 

* Argument (인자)
: 함수와 메서드의 입력 값(Value)

 
* Parameter (매개변수)
: 함수와 메서드 입력 변수(Variable)명

 
 

[(참고용) lexical과 비슷한 개념] Computer Programming Tokenization

 
 
* lexical (렉시컬)
: 변수를 검색할 때 함수가 실행되는 환경을 근거로 판단하는 것이 아닌, 함수를 정의한 코드의 문맥을 근거로 판단하는 것
  (const, 변수명, function 등) 컴퓨터가 단어 하나하나 인식하며 코드를 읽는 것
  └  Lexical Scope (렉시컬 스코프): 함수가 어디서 선언됐는지의 따라 상위 scope를 결정! (JS를 비롯한 대부분의 프로그래밍 언어가 렉시컬 스코프를 따름)
 

 
parsing (파싱)
: 기존의 데이터를 다른 형태 or 패턴으로 가공하는 것
 
문장이 이루고 있는 구성 성분을 분해하고 분해된 성분의 위계 관계를 분석하여 구조를 결정하는 것
즉, 데이터를 분해 및 분석하여 원하는 형태로 조립하고 다시 빼내는 프로그램! 웹상에서 주어진 정보를 내가 원하는 형태로 가공한 뒤, 서버에서 불러들이는 것
ex. 자료형 변환(JS list → JSON, JSON →  String 등) 
 
 
다음으로, 실행 컨텍스트를 이해하는 데 필요한 다른 개념도 알아보자. 아래 개념을 이해하면 React의 웬만한 개념 모두 이해가 가능하다고 볼 수 있다.
 

(1) ReferenceError (레퍼런스 에러)

: 현재 범위에서 존재하지 않거나 초기화되지 않은 변수를 참조했을 때 발생하는 에러
참조 에러! 객체는 존재하지 않는 변수를 참조했을 때 발생하는 에러를 나타낸다. 객체를 생성하지 않았기 때문에 참조할 값을 찾지 못했다고 이해하면 쉽다.
 

Undefined와 ReferenceError의 차이점?

Undefined

  • undefined 속성은 Undefined 원시값을 나타내며, JS의 원시 자료형 중 하나
  • 기본적으로 값이 할당되지 않은 변수는 Undefined 타입이며, Undefined 타입은 변수 자체 값 또한 undefined다. 
  • 변수는 선언했지만 초기화를 하지 않아서 그 값을 원시값인 undefined로 주는 것. 엄밀히 말하면 오류가 아니라 초기화가 되지 않은 것이다.

 
 
한 발자국만 더 나아가 보자.
노답 삼형제를 더 잘 이해하기 위해선, this를 정확하게 알고 있는 게 중요하다. this에 대해 알아보자.

 

this 

: 함수 내에서 함수 호출 맥락(context)
 

  • 함수를 어떻게 호출하느냐에 따라서 this가 가리키는 대상이 달라진다.
  • 함수와 객체의 관계가 느슨한 자바스크립트에서 this는 이 둘을 연결시켜주는 실질적인 연결점 역할
  • this는 상위 객체를 가르킨다. apply, call을 활용해 제어 가능

 

  • 자바스크립트에서 모든 함수는 객체란 사실을 명심하자. 그러므로 생성자 함수 또한 객체다.
  • 생성자 함수new 키워드와 함께 쓰이는 함수로, 직접 정의하여 new 키워드로 생성자 함수를 만들어 사용할 수도 있고, 내장된 생성자 함수를 사용할 수도 있다. ([JS 내장된 생성자 함수 3가지] new Array(); new Object(); new Function();)
  • 자바스크립트에서 객체란 속성(key)과 값(value)을 가지는 존재

 
 
▼  예문

// 우리가 여태 함수를 정의한다고 알고 있었지만 사실은 함수 객체를 만든 것임. 이것을 '함수리터럴'이라 한다.

function sum(x, y) {
  return x + y;
}
let sumResult = sum(2, 3);
document.write(sumResult + "<br/>");

// Function이라는 이름의 생성자 함수를 통해 메소드를 정의했다. 
// 마지막에 오는 인자가 바로 메소드의 본문에 해당한다. 앞의 요소들은 매개변수다.
const sum2 = new Function("x", "y", "return x + y;");
sum2(2, 3);
let sumResult2 = sum2(3, 4);
document.write(sumResult2);

// 객체 리터럴
// 위 아래 코드 모두 빈 객체를 만드는 같은 동작을 한다. 
const o = {};
const o1 = new Object(); // [차이점] JS 내장된 생성자 함수를 이용하여 객체를 만든 것

// 배열 리터럴 
// 객체 리터럴의 설명과 같음
const a = [1, 2, 3];
const a1 = new Array(1, 2, 3);

 
 

함수 호출

  • 어떠한 객체에 소속되어 있지 않은 함수를 호출했을 때 this는 무엇을 가리키는가?  ⇒  this === window 
  • 사실상 window가 생략됐을 뿐이지(암시적으로 사용되고 있는 window), window가 해당 함수를 포함하는 전역객체인 것

 

메소드의 호출

  • 객체의 소속인 메소드의 this는 그 객체를 가르킨다. 
  • e.g) o.func(); // 에서 this 란 o객체를 말한다.

 

생성자의 호출

  • 생성자는 빈 객체를 만든다. 그리고 이 객체 내에서 this는 만들어진 객체를 가르킨다.
  • 생성자가 실행되기 전까지는 객체는 변수에도 할당될 수 없기 때문에 this가 아니면 객체에 대한 어떠한 작업을 할 수 없기 때문이다.

 
 

(2) Event Loop (이벤트 루프)

 
: [브라우저 동작을 제어하는 관리자] 싱글 스레드인 자바스크립트의 작업을 멀티 스레드로 돌려 작업을 동시에 처리시키게 하거나 여러 작업 중 어떤 작업을 우선으로 동작시킬 것인지 결정하는 세심한 컨트롤을 하기 위해 존재
 

  • 비동기 프로그래밍의 핵심
  • 브라우저 내부의 Call Stack, Callback Queue, Web APIs 등의 요소들을 모니터링하면서 비동기적으로 실행되는 작업들을 관리하고, 이를 순서대로 처리하여 프로그램의 실행 흐름을 제어한다.

 

마치 순회(loop)하는 듯하여 이벤트 루프임

 
 
이벤트 루프의 동작 과정을 간단히 살펴보자면,
① 자바스크립트의 setTimeout이나 fetch와 같은 비동기 자바스크립트 코드를 브라우저 Web APIs에게 맡긴다.
② 백그라운드 작업이 끝난 결과를 콜백 함수 형태로 큐(Callback Queue)에 넣고 처리 준비가 되면
③ 호출 스택(Call Stack)에 넣어 마무리 작업을 진행한다.
 
이러한 이벤트 루프를 이용한 프로그램 방식을 '이벤트 기반(Event Driven) 프로그래밍'이라고 한다. 프로그램의 흐름이 이벤트에 의해 결정되는 방식이다. 예를 들어, 사용자의 클릭이나 키보드 입력과 같은 이벤트가 발생하면 그에 맞는 콜백 함수가 실행한다. 대표적으로 자바스크립트의 addEventListener(이벤트명, 콜백함수)가 있다.
 
 

[장점]

  • 이벤트 기반 프로그래밍으로 비동기 작업을 쉽게 처리 가능
  • 멀티 스레드 언어에 비해 단순하고 직관적인 코드 작성 가능
  • 브라우저와 같은 환경에서도 안정적인 실행을 가능하게 하여 사용자와의 상호작용을 높일 수 있음
  • 따라서 이를 이해하고 적절한 방식으로 비동기 작업을 처리하는 것은, 자바스크립트를 이용한 웹 애플리케이션 개발에 있어서 매우 중요

 
 

(3) PointerEvent (포인터 이벤트)

: 특정 요소에서의 클릭 이벤트를 동작하지 않도록 제어 가능
포인터에 의해 발생한 DOM 이벤트의 상태, 즉 접촉점의 위치와 크기, 이벤트를 유발한 장치의 유형, 접촉면에 가해진 압력을 나타냄
 
CSS를 사용하여 클릭 이벤트를 제어할 수 있는데, 그 방법 중 하나가 바로 CSS 프로퍼티인 pointer-events다.
 

  • none: 클릭 이벤트를 적용하지 않음
  • auto: 브라우저 자동으로 선택
  • inherit: 상속되어짐

 
 
▼  예문

.prevent-click { pointer-events: none; }

 
 

[필요한 상황]

애니메이션이나 복잡한 인터렉션 구현 시 각각의 엘리먼트 요소가 중첩될 수 있는데 이 경우, 클릭 영역이 가려져 동작하지 않는다. 이를 방지하기 위해서 pointer-events 속성이 필요하다.
 
 
 
[Reference]
1) https://taenami.tistory.com/109
2) https://m.blog.naver.com/dlaxodud2388/222655214381
3) https://velog.io/@party3205/JavaScript%EC%8A%A4%EC%BD%94%ED%94%84%EB%A5%BC-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90
4) https://poiemaweb.com/js-scope
5) https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError
6) https://developer.mozilla.org/ko/docs/Web/JavaScript/Event_loop
7) https://developer.mozilla.org/ko/docs/Web/API/PointerEvent
8) https://blueprint-12.tistory.com/105
9) https://inpa.tistory.com/entry/%F0%9F%94%84-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84-%EA%B5%AC%EC%A1%B0-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC#%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8_%EB%B9%84%EB%8F%99%EA%B8%B0%EC%99%80_%EC%9D%B4%EB%B2%A4%ED%8A%B8_%EB%A3%A8%ED%94%84
10) https://webisfree.com/2019-03-14/css-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-pointer-events-property
 
 
 

   2) Closure(클로저)

: Lexical 환경을 기억하는 함수!
함수 + 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)의 조합
 
즉, 외부 변수를 기억(참조)하는 기능이며 이러한 기능을 하는 함수가 될 수도 있다.

위 정의에서 말하는 '함수'란 반환된 내부함수를 의미하고, '그 함수가 선언될 때의 렉시컬 환경(Lexical environment)'이란 내 함수가 선언됐을 때의 Scope(스코프)를 의미한다. 즉, 클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 뜻한다.

 
'변수'에 접근이 되냐, 흐름을 읽어올 수 있냐로 이해해도 된다.


의미만 보면 무슨 말인가 싶다. 예제를 보며 이해해 보자.

function outerFunc() {
  var x = 10;
  var innerFunc = function () { console.log(x); };
  innerFunc();
}

outerFunc(); // 10

 
 
Scope는 함수를 호출할 때가 아니라 함수를 어디에 선언하였는지에 따라 결정된다. 이를 렉시컬 스코핑(Lexical scoping)이라 한다. 위 예제의 함수 innerFunc는 함수 outerFunc의 내부에서 선언되었기 때문에 함수 innerFunc의 상위 스코프는 함수 outerFunc이다. 함수 innerFunc가 전역에 선언되었다면 함수 innerFunc의 상위 스코프는 전역 스코프가 된다. '들여쓰기'를 기준으로 { } 중괄호를 본다면 scope의 상위, 하위 범위를 좀 더 잘 이해할 수 있다.
 
 
상위 스코프에 접근할 수 있는 것은 렉시컬 스코프의 레퍼런스를 차례대로 저장하고 있는 실행 컨텍스트의 Scope chain(스코프 체인)을 자바스크립트 엔진이 검색하였기에 가능한 것이다. (* Scope Chain: 욕심쟁이. 내 것도 내 거, 공공재도 내 거.. '단비'라고 봐도 됨. 근데 제일 가까운 거 쓰는 것을 좋아하고 지역변수를 전역변수보다 우선순으로 참조)
 
 
위 예제를 좀 더 자세히 설명하면 아래와 같다.

  1. innerFunc 함수 스코프(함수 자신의 스코프를 가리키는 활성 객체) 내에서 변수 x를 검색한다. 검색에 실패하였다.
  2. innerFunc 함수를 포함하는 외부 함수 outerFunc의 스코프(함수 outerFunc의 스코프를 가리키는 함수 outerFunc의 활성 객체)에서 변수 x를 검색한다. 검색에 성공하였다.

 
이번에는 내부함수 innerFunc를 함수 outerFunc 내에서 호출하는 것이 아니라 반환하도록 변경해 보자.

function outerFunc() {
  var x = 10;
  var innerFunc = function () { console.log(x); };
  return innerFunc;
}

/**
 *  함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다.
 *  그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
 */
var inner = outerFunc();
inner(); // 10

 
 
함수 outerFunc는 내부함수 innerFunc를 반환하고 작업을 종료했다. 
즉, 함수 outerFunc는 실행된 이후, 콜스택(실행 컨텍스트 스택)에서 제거되었으므로 함수 outerFunc의 변수 x 또한 더이상 유효하지 않게 되어 변수 x에 접근할 수 있는 방법은 달리 없어 보인다. 그러나 위 코드의 실행 결과는 변수 x의 값인 10이다. 이미 life-cycle이 종료되어 실행 컨텍스트 스택에서 제거된 함수 outerFunc의 지역변수 x가 다시 부활이라도 한 듯이 동작하고 있다.
 
이처럼 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우,
외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있는데 이러한 함수를 클로저(Closure)라고 부른다.
 
 

실행 컨텍스트의 활성 객체(Activation object)와 클로저

 
 
위 사진처럼 값을 갖고 오는 게 아니라 값을 갖고 있는 주소를 가리키며, 그 주소에게 간다 ⇒ 이를 '참조한다'고 표현한다.

실행 컨텍스트의 관점에서 설명하면, 내부함수가 유효한 상태에서 외부함수가 종료하여 외부함수의 실행 컨텍스트가 반환되어도, 외부함수 실행 컨텍스트 내의 활성 객체([Activation object] 변수, 함수 선언 등의 정보를 가지고 있다)는 내부함수에 의해 참조되는 한 유효하여 내부함수가 스코프 체인을 통해 참조할 수 있는 것을 의미한다.

즉, 외부함수가 이미 반환됐어도 외부함수 내의 변수는 이를 필요로 하는 내부함수가 하나 이상 존재하는 경우, 계속 유지된다. 이때, 내부함수가 외부함수에 있는 변수의 복사본이 아니라 실제 변수에 접근한다는 것에 주의하여야 한다.
  
 

* Closure가 유용하게 사용되는 상황!

상태 유지: 현재 상태를 기억하고, 변경된 최신 상태를 유지
② 전역 변수의 사용 억제
[중요] 정보의 은닉

불변성(Immutability)을 지향하는 함수형 프로그래밍에서
부수 효과(Side effect)를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이기 위해 클로저는 적극적으로 사용된다.
 
 
▼  예문 2개

const React = (function () {
	let hooks = [];
    let idx = 0;

    function useState(initVal) {
      const _idx = idx;
      console.log(_idx) // 0, 1

      const state = hooks[idx] || initVal;

      const setState = newVal => {
      hooks[_idx] = newVal;
      };

      idx++;
      return [state, setState];
    }

    function render(Component) {
      idx = 0;
      const C = Component();
      C.render();
      return C;
    }

  return { useState, render };
  })();

    function Component() {
      const [count, setCount] = React.useState(1);
      const [text, setText] = React.useState('apple');

      return {
        render: () => console.log({ count, text }),
        click: () => setCount(count + 1),
        type: (word) => setText(word),
      }
    }

    var App = React.render(Component); // {count: 1, text: "apple"}
    App.click();
    var App = React.render(Component); // {count: 2, text: "apple"}
    App.type('pear');
    var App = React.render(Component); // {count: 2, text: "pear"}

 

// Example 1
function Counter() {
  const [count, setCount] = useState(0) // same useState as above
  return {
    click: () => setCount(count() + 1),
    render: () => console.log('render:', { count: count() })
  }
}

const C = Counter()
C.render() // render: { count: 0 }
C.click()
C.render() // render: { count: 1 }



[Reference]
1) https://poiemaweb.com/js-closure
2) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
3) https://stackoverflow.com/questions/69528217/is-this-how-closure-works-in-usestate-hook
4) https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/
▶ [3, 4] 클로저(React Hook) 사용한 예시 링크
 
 
 

   3) Scope(스코프)  ⇒  { } 중괄호

: 변수의 유효 범위

 

{ } scope 유효 범위! (위부터 &amp;lt;전역&amp;gt;, &amp;lt;1번째&amp;gt;, &amp;lt;2번째&amp;gt; 순서)

 

Scope 종류

  1. Global Scope
  2. Function Scope
  3. Block Scope : 중괄호로 시작하고 끝나는 단위

 

  • 전역변수: 전역 컨텍스트의 LexicalEnvironment가 담긴 변수
  • JS는 기본적으로 함수가 선언되는 동시에 자신만의 scope를 가짐
  • 중첩 가능 (함수 안에 함수 넣을 수 있음)
  • Global Scope는 최상단 Scope로, 전역변수는 어디서든 접근이 가능
  • [우선순위] 지역변수 > 전역변수 (귀찮아서 가까운 애 데려간다고 이해하면 쉬움)
  • outerEnvironmentReference는 해당 함수 선언된 위치인 LexicalEnvironment를 참조
  • 전역 컨텍스트의 LexicalEnvironment까지 탐색해도 변수 찾지 못하면 undefined 반환

 
 
[Reference]
https://velog.io/@denmark-choco/javascript-Scope
 
 
 

3. 금일 소감

어엇... 정리를 깊게는 아니지만 일단 대략적으로 끝내고 나니... 지금 시각 07:05다.. 어쩌다 보니 또 날을 새워버린.... 집중하다 보면 종종 이렇게 되는 것 같다. 막 '오늘은 공부를 끝장낼 거니 밤을 새우겠어!' 하고 굳은 다짐으로 새우는 게 아니라 '몰입해 공부하다 보니 해가 떴습니다.' 이런 느낌이다. 하지만 좀 이따 공부에 집중이 안 될 정도로 어지럽거나 졸리면 낮잠 좀 자야겠다. 밤새운 건 건강에 좋지 않지만 어려운 노답 삼대장을 나름대로 정리해서 지금 기분은 좀 좋다 ㅎㅎ
 
어려워서 꽤나 오래 걸렸다.. 아직 정확하게 안 게 아니라서 주말에 더 보충해서 공부해야겠다.
 
그리고 아직 this랑 일급 객체, hoisting, 쿠키랑 캐싱 차이 등 아직 정리해야 할 게 산더미라 주말에 전부 정리를 해야 한다. 엇.. 아 오늘 금요일이구나. 오늘 가능하면 해야겠다. 원래는 내일도 파이팅이어야 하지만 밤을 새워버린 관계로 오늘도 파이팅!!!

 

728x90