• JavaScript

[JS] JavaScript 개념 (자바스크립트 엔진, 원시형/참조형, Stack/Heap)

man_on 2022. 11. 28. 01:04
반응형
 

 

 

 


 

 

 

 

JavaScript 란?

 

 

 

JavaScript is a dynamic, weakly typed programming language which is compiled at runtime.

  • 자바스크립트는 런타임에 컴파일되는 동적, weakly 프로그래밍 언어이다.
  • browser 에서 webpage의 일부로 실행될 수도 있고, host환경이라 불리는 모든 머신에서 직접 실행될 수도 있다.

 

JavaScript was created to make webpages more dynamic.

  • 자바스크립트는 웹페이지를 보다 동적으로 만들기 위해서 생성되었다.
  • 새 페이지를 로드하지 않고도 웹사이트의 내용을 변경할 수 있도록 브라우저에서 실행된다.

 

 

* 최초에는 LiveScript라고 불렸는데, 당시 Java의 인기로 인해서 Java와의 유사성을 꾀하기 위해서 JavaScript로

이름이 변경되었다고 한다. 하지만 둘 사이에는 전혀 공통점 없음!

 

 


 

 

자바스크립트는 호스트 환경에서 실행된다.

 

Browser-side

JS는 웹사이트를 보다 동적으로 만든다.

백그라운드 http요청을 보내는 등의 다양한 역할을 할 수 있다.

보안상의 이유로 로컬 파일 시스템에 엑세스할 수 없으며 운영체제 등과 상호작용 할 수 없다.

 

 

Server-side

브라우저를 위해 JS가 개발되었지만, 브라우저에만 국한되지 않는다.

google이 개발안 JS 엔진 V8은 어디에서나 JS가 실행할 수 있도록 추출되었다. → Node.js

node.js는 local filesystem에 접근과 파일 작성 등의 작업이 가능하며 운영체제와 상호작용이 가능하다.

로드된 웹페이지에 직접 접근할 수 없기 때문에 HTML이나 CSS의 조작은 불가능하다.

 

 

 

 

 

 


 

 

 

JS특징 - Dynamic,  Weakly typed

 

 

 

자바스크립트는 동적 해석형 언어이면서 약형 프로그래밍 언어이다.

JS는 동적 해석형 언어이면서, 약형 프로그래밍 언어이다.

 

Dynamic, interpreted Programming Language

동적 해석형 언어란, 미리 컴파일되지 않으며 최종적으로 유저에게 공유되기 전에 컴파일된다.

전송중에 컴파일되기 때문에 코드가 runtime에 평가되고 실행된다.

코드가 runtime에 변경되어 데이터 유형이 동적으로 전환될 수 있다. (→ TypeScript를 쓰는 이유)

 

 

Weakly Typed Programming Language

자바스크립트에서 텍스트나 숫자와 같은 데이터로 작업 시 데이터 유형을 가정하여, 자동으로 유추된다.

(다른 언어에서는 변수가 보유할 데이터 유형을 미리 정의한다.)

 

 

 

 

 

 

 


 

 

 

 

 

 

JavaScript Engines & What They do

 

 

 

Browser에는 코드를 가져와서 compile하고 최적화하여 실행하는 JavaScript 엔진이 있다.

 

 

 

 

Chrome과 같은 browser에는 JavaScript 엔진이 내장되어 있다. (크롬-V8 / 파이어폭스-SpiderMonkey)

그 엔진은 JavaScript 코드를 분석하여 읽고 이해하여 Machine Code로 compile 한다.

코드를 읽기는 하지만 이를 실행하는 것이 아니라,

해당코드를 머신에서 실행이 더욱 빠른 코드로 컴파일링 한 뒤 머신 코드를 실행한다.

이 모든 작업은 single thread에서 실행된다.

 

* 오늘날 엔진은 최적화가 많이 이루어져 있기 때문에, 엔진이 컴파일되지 않은 코드를 실행하기 시작한 후

더 빠른 실행을 시작하기 위해서 이미 실행중인 코드를 컴파일 할 수도 있다.

그 다음 컴파일된 코드로 동적으로 전환하는 등의 작업이 일어난다.

 

 

 

 


 

 

 

[JS코드 작성 후 작동하는 과정]

우리가 작성한 JS코드를 HTML파일에 import하면 Browser가 해당 HTML파일을 읽음

→ script를 감지하여 import 하고 실행한다. (세부사항은 브라우저와 엔진에따라 다르게 수행한다.)

→ JavaScript Parsing : 브라우저가 JS 코드를 읽어 들여서 로딩 (분석)

→ Execution : 실제로 코드가 실행

→ compiled machine code는 컴퓨터로 전달되어 실행된다.

 

Parses script & starts execution (JS Engines이 실행)

Interpreter
: script를 load하고 읽어들여서 이를 실행하기에 좀 더 쉬운 바이트코드로 변환한 다음 스크립트 실행을 시작하고, 
  변환된 바이트코드를 compiler에 전달한다.

Compiler (JiT = Just in Time)
: script를 머신코드로 컴파일한다.  
(JIT 컴파일러는 코드를 읽고 실행 중에 컴파일링을 시작하고 동시에 컴파일 된 코드를 실행한다.)

 

 

* Browser는 실행 및 컴파일링 시간을 단축하여 최적하 하기 위하여,

이전 실행과 현재 실행 시 코드가 달라진 부분이 없다면, 컴파일링을 다시 하지않고 컴파일된 이전 코드를 다시 사용하게 된다.

 

 

 

 


 

 

 

 

 

 

How code gets executed ?

 

 

자바스크립트 코드 실행 시 어떤 단계가 뒤따르고, 이 때 실행되는 원리에 대해 알아본다.

 

JS 엔진의 2가지 중요 개념

Heap  장기 메모리
: 시스템 (장기) 메모리 데이터를 저장 (브라우저가 관리)

Stack  단기 메모리
: 프로그램의 흐름을 관리, (브라우저, JS engine이) 현재 실행하는 함수를 관리하는 역할 (=함수 실행 내역이 저장)

 

Heap

  • 함수 자체는 힙에 저장된다.

 

Stack

  • JS가 전체 스크립트를 평가한 뒤 (= 모든 함수의 정의를 확인한 뒤) 스크립트가 실행되면 스택이 활성화된다. 
  • 스택은 익명 코드 실행부터 시작된다. ( 스크립트 파일 자체, 이름을 따로 지정해놓지 않은 거대한 함수)
  • 스택은 JS엔진이 현재 수행하는 작업을 기록하는 곳이다.
  • 새로운 함수 호출이나 단기 데이터를 push해서 채우고, 함수가 return 하거나 실행을 마쳤을 때 삭제된다.
  • 스택에서는 맨 위의 항목이 항상 현재 실행중인 항목이 된다.
  • 해당 함수의 정의가 Heap에서 제거되지는 않는다.
    (현재 실행된 사항에 대해서만 삭제되며, 이에 대해 할당했던 resource와 함수 실행을 위해 관리되야 했던 데이터까지만 제거된다.

 

→ 한 번에 하나의 함수만을 호출하고, 다른 함수는 그 함수의 응답을 기다린다.

함수의 실행 순서를 보장하고, 모든 함수가 어떤 함수와 관련되었는지를 알 수 있다.

= 자바스크립트는 싱글스레드이다.

 

 

 

 

 

[예시]

const getName = () => {
  return prompt('Your name: ' + '');
};

const greet = () => {
  const userName = getName();
  console.log('hello ' + userName);
};

greet();

 

전체 스크립트의 실행이 시작되고 나면, 먼저 익명 함수 실행이 있고,

→ greet 함수를 스택으로 이동 (익명함수의 위에 올려짐)

→ greet함수 안에서 getName을 호출 했으므로, JS 엔진이 getName함수를 스택에 push

→ getName안의 prompt가 스택으로 push (prompt는 브라우저가 제공한 함수)

→ prompt부터 (쌓여진 최상위부터) 함수가 실행되고 return 되면 하나씩 삭제

→ 익명 함수로 이루어진 스크립트 자체만 남으면 실행이 종료

 

크롬브라우저에서 prompt 실행됬을 때 쌓인 call stack
prompt에 입력 후 getName은 삭제

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

Primitive Values   /   Reference Values

 

 

 

 

Javascript는 크게 2가지 타입 Primitive 원시값reference 참조값으로 나눌 수 있다.

 

 

Primitive Values

6개의 자료형 String, Number, Boolean, null, undefined, symbol이 Primitive values에 해당하고,

이 것들은 메모리에 저장되고 보통 stack에 저장된다. (실행 시간이 긴 경우 heap으로 저장될 수도 있다.)

중요한 것은 참조값과의 차이 인데, primitive values는 변수를 복사할 때 새로운 변수에 그 값을 할당하고 실제로 그 값이 복사된다.

 

 

 

[예시]

변수 name에 'Kim'을 할당하고, anotherName에 name을 할당하면

이 때 name의 'Kim'을 그대로 복사하여 anotherName에 저장한다.

name을 다른 값으로 변경해도 name을 복사한 anotherName은 별도의 copy본을 가지고 있으므로 영향을 미치지 않는다.

 

 

 

 

 

Reference Values

Primitive values 6개의 자료형을 제외하고는 reference values라고 볼 수 있으며,

문자열이나 숫자보다 더 많은 데이터를 보통 가지고 있으므로 Heap으로 저장한다.

Primitive와 다르게, 값 자체가 아닌 메모리 공간의 주소만을 저장한다.

따라서 변수를 변수를 복사하면 값 자체가아닌 메모리 공간을 가리키는 pointer를 복사하여, 메모리에 저장된 객체를 참조하게 된다.

 

 

 

 

[예시1]

변수 name에 'Kim'을 할당하고, newPerson은 name을 복사한다.

name에 'Lee'를 추가하고 newPerson을 보면 name을 가리키는 pointer를 복사했기 때문에

name과 동일한 배열을 가지는 것을 볼 수 있다.

 

 

 

 

 

 

[예시2]

같은 형태의 객체를 가지고 있는 person1과 person2를 비교해보면 false값이 나오게된다.

같은 데이터를 가지고 있지만 이 둘은 서로 다른 메모리 공간의 포인터를 가지고 있으므로 완전히 다른 객체라고 볼 수 있다.

 

 

 

 

[예시3]

const로 배열을 만들어서 push로 새로운 데이터를 추가하면 const가 상수이기 때문에 오류가 발생해야 할 것 같지만,

배열은 참조형이기 때문에 name이 할당된 것은 해당 배열 또는 객체의 주소이기 때문에

push를 하더라도 메모리의 주소는 변경되지 않으므로 에러가 발생하지않고, 메모리의 데이터만 바뀌게된다.

 

 

 

 

 

 

 


 

 

 

 

 

Garbage Collection

 

 

 

stack보다 오래 저장되는 Heap은 overflow가 될 수 있으니 메모리가 관리가 중요하다.

컴퓨터의 운영 체제는 chrome같은 browser에 일정량의 메모리만을 할당하고, 초과되었을 경우 브라우저를 종료시킨다.

이런 강제종료가 일어나지 않게하기 위해서, 브라우저는 내부 메모리 관리를 하여 메모리가 초과되기 전에 웹사이트를 종료하는데,

이런 메모리 관리를 위하여 JS engines들이 가지고 있는 메모리 관리 방식을 Garbage Collention이라고 한다.

 

 

Garbage Collention의 역할

  • 사용되지 않는 객체에 대한 heap memory를 주기적으로 확인하여 메모리에서 제거한다.

 

 

 

 

 

 

 

 

 

 

 

 

반응형