자바스크립트 프로그래밍(in progress)

태현·2021년 5월 31일
1
post-thumbnail

🚓이 페이지는 JS 중급으로 가기위해 스터디한 기록들을 담아 놓았습니다.

들어가기 전에🙋🏻‍♂️


안녕하세요, 오늘은 JS 중급을 위한 첫 걸음을 시작해 볼까 합니다🚓
JS를 포함하여 현재 웹개발 시장은 너무나도 빠르게 변화하고 있습니다. 기술적인 측면뿐 만 아니라 웹 브라우저를 만드는 브라우저 제조사 bendor에서도 JS 표준화가 이뤄지기도 전에 새로운 기능을 탑재하고 더불어서 각종 프레임워크나 라이브러리들이 시장을 가득 메우고 있다는 소식들을 쉽게 접할 수 있습니다. 이러한 상황속에서 우리는 어떻게, 어떤 식으로 공부를 해야할까요? 그냥 흘러가는 대로 공부하는 것도 좋지만, 좀 더 시장 전체의 흐름을 알 수 있으면 좋겠다라는 생각을 항상 해왔습니다. 물론 개발보다도, 어떤 코딩보다도 비즈니스적인 사고와 사용자들의 편의성을 위한 생각을 꾸준하게 하는 것이 훨씬 더 중요하다는 사실도 잘 알고 있습니다. 다만, 저는 JS가 가진 힘을 인정하고 있어요. 꾸준하게 업데이트가 되는 것 만으로도 새롭게 알아야 할 것이 생기는 그 자체가 좋았습니다.😅 그리고 이제는 좀 깊이 알아야 할 시간이 온 것 같아요. JS를 시작한 지 3개월 차가 되는 이 시점에서 또 다시 어떻게 공부해야 할까요? 누군가에게는 전혀 쓸데없는 이 생각이 저에게는 하루를 리프레쉬하는 자극제가 되곤 합니다. 개발을 배우기 이전에도 이러한 생각을 통해서 머리속을 재배치 하곤 했습니다. 그럼, 긴 시간을 투자해서 JS 언어 자체를 공부하는 것이 리액트나 앵귤러, Vue를 공부하는 것보다 유의미한 것 일까요? 저는 그렇다고 봐요.
이번 포스팅에서는 굉장히 긴 내용을 다룰 것 같습니다. JS 동작원리와 핵심 키워드를 위주로 공유해 볼까 합니다. 제 글을 보시고 JS를 배우시는 모든 분들께 이 친구는 이런식으로 의미부여를 했구나 정도로만 참고해주시면 감사드리겠습니다, 시작할게요🚓

데이터 타입‼️


데이터 타입의 종류

먼저, JS를 공부하기 전에 가장 중요한 것이 바로 이 데이터 타입 입니다.가 외부로 부터 전달받는 인자가 어떠한 데이터 타입인지 아는 것부터가 코딩의 시작이라고 생각을 했어요. 그래서 우리가 첫 번째로 알아야 할 부분입니다.

데이터 타입은 크게 두 종류가 있습니다. 바로 Primitive TypeReference Type 인데요, 이는 다음과 같습니다.

  • 원시형(Primitive Type)
    • number, string, boolean, null, undefined, symbol(=ECMA Script6 추가)
  • 참조형(Reference Type)
    • object, array, function, date, regExp
      • map, weakMap, set, weakSet(=ECMA Script6 추가)

::왜 이렇게 따로 구별을 해놨을까요?

const num = 1;

const obj = {
	name: "march",
	age: 21
};
  • 원시형 데이터 타입은 불변성을 띄며, 값을 그대로 가리킴
  • 참조형 데이터 타입은 해당하는 값이 아닌, 레퍼런스(주소)를 가리킴

데이터 타입에 관한 배경지식

JS에서 데이터 타입을 따로 구별을 하는 것은 그 만한 이유가 있습니다. 그걸 이해를 하려고 하면 그냥은 안되요. 우리가 뭔가를 알고 있어야합니다.
컴퓨터는 모든 데이터를 0 또는 1로 바꿔서 기억합니다. 그런데, 0 또는 1로만 표현할 수 있는 하나의 메모리 조각을 비트 라고 불러요. 중요하지 않아요.
대신, 메모리는 이 비트들로 구성이 되어있어요. 그리고 각각의 비트는 해당하는 고유한 식별자를 통해 위치를 확인할 수 있습니다.

그런데 obejct를 0 또는 1인 비트만을 가지고 위치를 파악하고자 하는 것은 훗날 한계가 있겠죠? 그래서 이 비트를 어느정도 묶어버리자라고 생각을 하게 된 것입니다. 이제 바이트를 알았어요.

결국 저는, 아 오브젝트가 만들어지면 메모리에 바이트 사이즈가 따로 할당이 되고 👉 그 주소를 가르키는구나 라고 이해를 했습니다.

1bit (= 0 또는 1) 이며 , 1 byte (= 8bit)

<참고>

  • ✍️C/C++, 자바 같은 언어에서는... 메모리의 낭비를 최소화 하기 위해 데이터 타입별로 할당할 메모리를 따로 지정해 두었습니다. int 같은 키워드로 메모리를 조절할 수 있죠. 과거 컴퓨터 한 대의 메모리 용량이 부족했던 시절에는 어쩔 수 없었을 겁니다.
int = 1;
  • ✍️현재 자바스크립트 환경에서는... 메모리를 신경쓸 필요가 거의 없이 number하나면 끝 입니다. 굉장히 편리합니다.
const number = 1;
  • 🚨식별자 그리고 변수를 혼용하는 경우가 많아서... 이를 구별하는 것이 좋습니다. 변수란 변할 수 있는 데이터 를 말하며 식별자는 변수명 입니다.
const varibale = "변수";
      (식별자)

변수 선언과 데이터 할당

JS에서 왜 기본형과 원시형 데이터 타입이 따로 구별되어졌는지 그 이유는 알게 되었습니다. 0과 1의 집합체인 이 비트만을 가지고는 택도 없기 때문입니다. 오브젝트 때문이죠. 그래서 어느정도 메모리 감소를 받아들이고 비트를 모아놓은 바이트를 만들어야 겠다는 생각을 한 것입니다. 참고로, Java 나, C/C++에서는 낭비하는 메모리를 최소화하기 위해 또 무언가를 따로 하지만 JavaScript는 아니다라는 것을 알 수 있습니다.
그렇다면, 왜 구별 되어졌는지는 알게 되었으니, 우리가 선언한 변수와 데이터 타입은 어떤 식으로 연결되는 것일까요?**

::변수 선언과 데이터 할당! 이 전체 흐름을 좀 더 알기 쉽게 설명을 한다면?

//첫 번째
let number;
number = 1;
//두 번째
let number = 1;

위와 같은 예시에서는 첫 번째와 두 번째가 동일합니다. 그러나 실제로는 해당 위치에 숫자 1을 저장하지 않아요.
JS는 기본적으로 문자열이든 숫자열이던 상관 없이 무조건 새로운 공간에 데이터를 저장합니다. 당연히 메모리가 필요해요. 그래서 JS에서의 변수와 데이터 할당은 성능을 위해서 데이터 영역과 변수 영역을 따로 구분지어 놓습니다.

  • JS의 변수와 데이터 할당은 서로 별도의 공간에 저장해서 주소를 연결함

기본형 데이터와 참조형 데이터

::불변값

JS에서 불변값과 상수를 같은 개념으로 오해하기 쉬운데, 이는 다릅니다.
정확하게 짚어야 할 필요가 있어요.
간단하게 말해서 우리가 기본형(원시형) 데이터를 업데이트한다면, 그 자체를 바꾸는 것이 아니라 일단 저장을 해 놓고 새로 업데이트 되는 데이터를 찾아서 있으면 재활용하고, 없으면 새로 만들어서 저장하는 것입니다.
그래서 기본형 데이터들은 모두 불변합니다.

::가변값

그렇다면, 참조형 데이터는 모두 가변값일까요?
그런 경우가 많지만, 자세히 말하면 불변한 경우가 있고, 아예 불변값으로 활용하는 경우도 있습니다.
참조형 데이터가 기본형 데이터와 차이를 갖는 것은 객체의 프로퍼티 영역 이 따로 존재하는 것인데요, 이 부분 때문에 참조형 데이터는 가변값이다 라고 하는 것입니다. 그래서 참조형 데이터의 프로퍼티에 또 다시 참조형 데이터를 할당하는 이중 구조를 가지는 중첩 객체 이하 nested object 에서도 마찬가지로 기본형 데이터 타입이 아니고는 전부 주소값을 가르키고, 자신의 주소를 참조하는 변수가 없을 때, 즉 데이터를 가리키는 프로퍼티가 없을 때를 가비지 컬렉터 라고 하는데 가비지 컬렉터는 기본적으로 런타임 환경에서 우리가 특정 시점이나, 메모리 사용량이 포화 상태에 임박할 때마다 자동적으로 수거 대상들을 알아서 수거하고 그 메모리는 다시 새로운 값을 할당할 수 있는 빈 공간이 됩니다.

::변수 복사 비교

데이터 할당 다음으로 좀 더 자세한 기본형 데이터와 참조형 데이터의 차이는 다음과 같습니다.


👏🏻프로세스

CPU 자원을 받아 프로그램 내에서 연속적으로 실행되고 있는 프로그램

  • 운영체제 위에서 독립적으로 메모리에서 실행되는 프로그램
  • 각각의 프로세스는 저마다 리소스(메모리, 데이터) 자원들이 할당 되어져 있음

🙋🏻‍♂️프로세스 안에는?

  • 프로세스를 실행하기 위한 코드
  • 동작 순서인 스택
    : 함수들이 어떤 순서로 실행되어야 하는지, 어디로 가는지에 대한 정보 저장
  • 데이터들이 들어있는 힙과 데이터
    : 오브젝트를 생성하거나 데이터를 만들 때 데이터를 저장하는 공간

힙에는 동적으로 할당된 변수들이 저장 vs 데이터는 전역 변수나 스태틱 변수들이 할당


쓰레드💡

프로세스 안에 있는 일꾼, 일꾼이 많다면 동시에 할 수 있는 것들이 그만큼 많아짐

  • 함수 각각의 호출을 기억하기 위해 쓰레드마다 스택이 할당
  • 결국 프로세스 위해 존재하기 때문에 프로세스에 지정된 코드나 데이터 힙에 공통적으로 접근이 가능(업데이트 가능)
  • 예를들어, 앱에서 영상을 송출하면서 다른 것이 가능한 점
  • 쓰레드가 있기 때문에 다양한 일들이 가능

쓰레드는 스택, 프로세스는 자원이라는 컨셉이기 때문에 서로간에 공유하면서 사용됨

따라서 멀티쓰레딩을 잘 못하면 동시에 무언가를 할 때 순서가 맞지 않으면 발생할 수 있는 경우가 있음.


🙋🏻‍♂️멀티 쓰레딩?


멀티 쓰레딩으로 인해 효율적인 프로그래밍이 가능해짐

  • 지원여부⭐️⭐️⭐️⭐️⭐️

    • Java:

      • 서버에서 데이터를 받아오는 것 👉 쓰레드A에서 하겠다 등등이 가능
      • 쓰레드 동작 갯수 설정 가능
      • 그래서 자바로는 배워야 하는 것들이 많음
    • JS:

      • Single Threaded Language
      • JS언어 자체에는 멀티 쓰레딩x
      • 이 함수는 백그라운드에서, 이 함수는 쓰레드B 에서 등등이 불가
      • 그러나, 브라우저라는 프로그램 안에서는 여러가지의 쓰레드가 존재✨
      • 그래서 브라우저 웹APIs를 활용하여 멀티쓰레딩이 가능토록 하는 것✨
      • 그리고 JS가 동작하는 런타임 환경에서 즉, JS실행 환경에서는 APIs를 활용하는 것 뿐만 아니라 이벤트 루프를 이용해서 다양한 동작이 가능하도록 함✨

    JS런타임 환경💡

컨셉: 프로세스 안에는 힙과 스택이 있는 것과 동일하게 JS엔진에도 메모리 힙과 콜 스택 등이 있음


🙋🏻‍♂️메모리 힙과 콜 스택?

  • 메모리 힙:

    • 변수를 선언해서 오브젝트 문자 숫자를 할당하면 그 데이터들은 전부 다 메모리 힙에 저장
    • 구조적으로 정리된 자료구조x, 여기저기 아무곳에서나 저장됨
  • 콜 스택:

    • 우리가 함수를 실행하는 순서에 따라서 쌓아놓는 것
    • 함수들이 콜 스택에 차곡차곡 쌓여지고 호출되는 순서를 기억했다가 함수가 끝나면 쌓인 것들을 지우는 자료구조 중 하나
    • 모든 프로세스와 쓰레드는 각각 저마다의 콜 스택 사이즈 보유1
    • 재귀함수
      • 콜 스택을 잘못 쓰는 것을 재귀함수(함수안에서 자기 자신을 부름)
      • 재귀함수는 유용하지만 잘못 쓰면 콜 스택 사이즈 초과
    👉 스택: `LIFO(last-in-first-out)` 라고 불리며, `push``pop`, `peek` 같은 API가 있음

    JS 실행 환경💡(=JS전체적인 실행 환경)

멀티 쓰레딩도 안되는 JS는 기본적으로 할 수 있는 것이 매우 한정적이었음

그러나, 브라우저 웹 APIs를 통해 웹 개발을 JS로 할 수 있는 것

대표적, fetch() 또는 setTimeout() 이며 자료구조 큐의 형태


🙋🏻‍♂️어떻게 웹APIs와 JS엔진이 서로 동작하는 것?

  • 예를들어, 함수안에서 다시 setTimeout()을 호출했다고 가정

    • 호출하는 순간 setTimeout()은 콜백에서 지워짐
    • 웹 API는 타이머를 시작
    • 타이머 && JS 엔진은 병렬적 실행 👉 시간 끝나면 👉 웹 APIs는 태스크 큐에 콜백을 넣어줌
    👉 큐: `FIFO(first-in-first-out)` 라고 불리며, 대표적 API`add``remove`, 가 있음
  • 결국, 웹 APIs는 우리가 등록한 콜백 함수를 지정한 시간에 알아서 태스크 큐에 넣어줌

    • 🙋🏻‍♂️ 테스트 큐에 있는 콜백은 언제 실행?
      • : 이를 관찰하는 것이 바로 Event Loop(이벤트 루프)

👏 이벤트 루프?

  • 이벤트 루프는 돌면서 콜 스택이 비워질 때까지 기다림
  • 콜 스택이 텅텅 비어지면 (setTimeout()이 호출되고 실행되는 함수가 끝나면) JS가 더 이상 일을 하지 않을 때 이벤트 루프에 있는 timeout callback 을 실행
  • 결국, 이벤트 루프는 프로세스가 동작하는 동안(=비동기 함수가 처리되는 동안) 콜 스택이 비워져 있다면 태스크 큐에 있는 것을 콜 스택으로 가져오는 역할

이해x❓ 예제: 버튼에 이벤트리스너를 등록하고 클릭을 하면, 웹API는 이벤트 루프에 콜백함수를 테스크 큐에 넣음

그리고 버튼이 또 일어나면 콜백함수가 또 태스크 큐에 들어옴

이벤트 루프가 콜백 로직이 다 수행이 되는 걸 확인하고 나서 먼저 클릭된 콜백 하나를 콜 스택에 가져와서 실행함


🙋🏻‍♂️ 맥락 정리?

  1. JS엔진 동작과정

    웹 APIs에서 버튼 리스너 등록 ➡️ 이벤트 발생 ➡️ 웹 APIs가 태스크 큐에 콜백함수 등록 ➡️ 텅텅 빈 콜 스택 확인 -> 이벤트 루프가 태스크 큐에 있는 콜백함수 이동(태스크 큐 👉 콜 스택) ➡️ 콜백함수 실행

  2. 설명

자바스크립트 엔진에는 콜 스택이 있다: 콜 스택은 함수가 실행되는 과정을 기억하기 위해 쓰이는 자료구조

자바스크립트가 동작하는 런타임 환경에서는 태스크 큐마이크로 태스크 큐를 이용해서 비동기적 처리를 한다. : 태스크 큐는 한 번에 하나씩만 콜백 함수를 가져옴 // 마이크로 태스크 큐는 자기자신 안에 들어있는 모든 콜백 함수가 다 수행할 때까지 가져옴 // 랜더는 주기적으로(매번x) UI를 업데이트 하기 위해서 이벤트 루프가 자주 들러줌 // 우리가 호출한 RAF(request frame callback queue)는 업데이트가 일어나기 전에 쭉 순회하면서 코드가 실행됨. 그래서 똑같은 RAF가 여러개 있을 때에는 최종적인 RAF함수의 코드블럭이 적용됨


출처:

profile
안녕하세요, 지식을 공유하는 공간입니다.

0개의 댓글