반응형

변수

변수하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름을 말한다.

식별자

변수를 식별자라고도 부른다, 식별자는 어떤 값을 구별해서 식별할 수 있는 고유한 이름을 말한다.

식별자는 값이 아니라 메모리 주소를 기억하고 있다.

var result = 10 + 20;

위의 코드 동작을 실행했을 때 result는 10 + 20이 저장되어있는 메모리의 주소(0x0000ffff 예시)를 알고있다.

즉 메모리 주소에 붙인 이름을 식별자라고 할 수 있다.

식별자라는 용어는 변수 이름에만 국한해서 사용하지 않고, 변수, 함수, 클래스 등은 모두 식별자라고 부를 수 있다.

메모리 상에 존재하는 어떤 값을 식별할 수 있는 이름은 모두 식별자라고 부른다.

자바스크립트에서 10 + 20을 어떻게 계산하는가?

자바스크립트 엔진이 10+20의 값을 계산하기 위한 동작과정

    • 연산을 수행하기 위해 먼저 + 연산자의 좌변과 우변의 숫자 값, 즉 피연산자를 기억
  • CPU를 활용해 연산하고 메모리를 통해 데이터를 기억
    • 메모리는 데이터를 저장할 수 있는 메모리 셀의 집합체다.
    • 메모리 셀 하나의 크기는 1바이트 즉 1바이트 단위로 데이터를 저장하거나 읽어들인다
  • 각 셀은 0xFFFFFFFF 등과 같은 메모리 주소를 가지며, 메모리 공간의 위치를 나타낸다.
    • 0x00000000 ~ 0xFFFFFFFF
  • 위 예제의 숫자 값 10과 20은 메모리 상의 임의의 위치(메모리 주소)에 기억되고 CPU는 이 값을 읽어들여 연산을 수행한다. 연산 결과로 생성된 숫자 값 30도 메모리 상의 임의의 위치에 저장한다.

ex ) a = 10, b = 20, a + b = 30

각각 임의로 a = 0x0000ffff, b = 0x0000fffc 의 주소가 있다고 했을 때
a + b 의 코드가 실행되면 cpu에서 a의 주소, b의 주소를 참조하여 계산 후 임의의 주소 어딘가에
10 + 20의 결과값 30을 넣어둔다. 이 때 30을 변수에 저장한다면 메모리에서 저장해둔 채로 둘 수 있고,
변수에 저장하지 않는다면 1회성으로 사용 후 찾기 어렵다.

 


변수 선언

변수 선언을 하면, 하드웨어 에서는 값을 저장하기 위한 메모리 공간을 확보하고, 변수 이름과 확보된 메모리 공간의 주소를 연결시켜둔다.

변수를 선언할 때는 var, let, const 키워드를 사용한다 ES6에서 let, const 키워드가 도입되기 이전까지 var 키워드는 자바 스크립트에서 사용할 수 있는 유일한 키워드였다.

Var 키워드의 단점

  • 변수의 스코프 문제
  • 호이스팅(hoisting)
  • 중복 선언 허용

변수 단원이기에 세가지 큰 문제중 하나를 다루자면, 변수의 스코프 문제가 있다.

ES6에서 let과 const 키워드가 도입된 이유

var 키워드는 블록 레벨 스코프를 지원하지 않고 함수 레벨 스코프를 지원하는 것으로 의도치 않게 전역 변수가 선언되어 자주 부작용이 발생했다.

ES6에서 let과 const가 나왔지만 var가 사라지지는 않았는데, 이 이유는 이미 구현된 ES6 이전의 js코드들은 모두 var로 선언되었기 때문에 호환성 등을 위해 남겨두고 폐기시키지 않았다. 하지만 위의 설명과 같은 이유로 권장하지 않기에 사용을 지양

변수 선언과 메모리 관계

변수를 최초 선언 시에는 메모리주소를 정하고 공간을 확보했을 때 따로 넣는 값이 없다면 자바스크립트 에서는 undefined의 값이 해당 메모리 공간에 들어가 있다.

때문에 자바스크립트 엔진에서는 변수 선언을 2단계에 거쳐 수행한다.

  • 선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
  • 초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.

초기화 단계의 중요성

초기화 단계를 통해 undefined를 할당해 초기화 하는 이유는 초기화 단계를 거치지 않았을 때 확보된 메모리 공간에 이전에 사용했던 값이 남아있을 수 있기 때문.

할당 된 변수 이름들은 자바스크립트 실행 컨텍스트에 등록된다.

실행 컨텍스트

실행 컨텍스트는 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위해 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역으로 실행 컨텍스트를 통해 식별자와 스코프를 관리한다.


변수 선언의 실행 시점과 변수 호이스팅

console.log(score);

var score; // 변수 선언

위의 코드를 실행하면 선언 시점이 score를 사용하는 console.log보다 늦었기에 참조 에러ReferenceError가 발생할 것처럼 보이는데, 자바스크립트에서는 undefined가 출력된다.

  • 변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 시점, 런타임 시점이 아니라 그 이전 단계에서 먼저 실행되기 때문이다.

자바스크립트 엔진은 소스코드 실행을 위한 준비 단계인 소스코드의 평가 과정에서 모든 선언문(변수 선언문, 함수 선언문 등)을 소스코드에서 찾아내 먼저 실행한다. 평가 과정 이후 변수 선언을 포함한 모든 선언문을 제외하고 소스코드를 한 줄씩 순차적으로 실행한다.

즉 자바스크립트 엔진은 변수 선언이 소스코드의 어디에 있던지 다른 코드보다 먼저 실행된다. 따라서 변수 선언이 소스코드의 어디에 위치하는지와 상관없이 어디서든지 변수를 참조할 수 있다.

이처럼 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 호이스팅(variable hoisting)이라 한다.


값의 할당

변수에 값을 할당(대입, 저장)할 때는 할당 연산자(=)를 사용한다.

var score = 80;

이 때 호이스팅 관련해서 주의할 점이 변수 선언 까지만 호이스팅 되고, 값의 할당은 실제 스크립트를 한줄씩 읽는 런타임 때 할당된다.

console.log(score); // undefined

var score; // 변수 선언
score = 80; // 변수 할당

var score = 80; // 변수 선언 및 할당

console.log(score); // 80

위의 예제에서 두 소스코드 모두 동일하게 undefined, 80으로 결과값이 같다.

  • 메모리 관점
    • 변수 선언과, 값의 할당은 서로 다른 메모리에 저장
    • 즉 score 식별자는 메모리 공간에 할당된 주소만 볼 뿐

console.log(score); // undefined

score = 80;
var score;

console.log(score); // 80

상수

값을 재할당 하지 못하게 하는 것

var score = 80; //변수 선언과 값의 할당
score = 90; //값의 재할당

엄밀하게 말하면 score = 80;의 시점부터 재할당이 된 것이다.
때문에 자바스크립트에서의 상수는 명확하게 말하면 한번 정해지면 변하지 않게 하는 값

ES6에서는 const 키워드를 사용해 상수 선언을 할 수 있다.

출처 : 모던 자바 스크립트 Deep Dive

반응형
반응형

자바스크립트 실행 환경

모든 브라우저와 Node.js에서 ECMAScript를 실행할 수 있다.
하지만 ECMAScript 외의 기능들은 호환되지 않는다.

예) 브라우저에서 활용하는 자바스크립트 DOM API

// ECMAScript 코드
const button = document.getElementById('myButton'); // DOM API 사용

// ECMAScript 함수 정의
button.addEventListener('click', () => { // DOM API 사용
  alert('Button clicked!'); // ECMAScript 내장 함수 사용
});

Node.js가 DOM API를 활용하지 않는 이유는 Node.js역할과 관련있다.
Node.js는 브라우저 외부 환경에서 동작하는 백단의 구현을 위한 실행 환경 이기에 Core 언어로 제공하지 않으며, 필요한 경우 라이브러리를 사용해서 HTML문서를 가공할 수 있다.

백단에서 사용하는 우리가 아는 언어들은 모두 파일 시스템을 기본적으로 제공하는 것처럼 Node.js환경에서는 이를 동일하게 제공한다(Javascript범주). 하지만, 브라우저에서는 이런 파일 시스템을 기본 제공하지 않는다.(FileReader로 읽기동작은 가능)

제공하지 않는 이유 : 브라우저에서 동작하는 자바스크립트가 사용자의 파일을 임의로 다룰 수 있다면 사용자의 파일을 보안 공격으로 쉽게 공격할 수 있음

위에서 이야기한 내용을 정리하면

  • 브라우저
    • ECMAScript
    • DOM
    • BOM
    • Canvas
    • XMLHttpRequest
    • fetch
    • ….
  • Node.js
    • ECMAScript
    • 클라이언트 사이드 API(DOM …)를 미지원


Node.js와 NPM

  • Node.js : 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임 환경
    ⇒ 서버 사이드 개발이 가능
  • NPM(Node Package Manager) : 자바스크립트 패키지 매니저로 Node.js에서 사용할 수 있는 모듈을 패키지화해서 모아둔 저장소 역할, 패키지 설치 및 관리를 위한 CLI를 제공
반응형
반응형

자바스크립트의 표준화

자바스크립트가 나온 초창기에는 자사 브라우저의 시장 점유율을 높이기 위해 자사 브라우저에만 동작하는 기능들을 추가했는데, 이로 인해 브라우저에 따라 웹페이지가 정상적으로 동작하지 않는 크로스 브라우징 이슈가 발생

이로 인해 비영리 표준화 기구인 ECMA 인터네셔널에서 자바스크립트 표준화 진행되어, 표준화된 자바스크립트 버전인 ECMAScript의 최초버전인 ES1이 등장

이후 ES2 버전에서는 ISO/IEC 16262 국제 표준과 동일한 규격을 적용하며 계속 버전업 되어왔음

자바스크립트 버전별 변천사

  • ES3(1999) → 정규 표현식, try catch
  • ES5(2009) → HTML5와 함께 등장 JSON, 배열조작(forEach, map 등), map, set
  • ES6(2015) → let/const, 클래스, 화살표 함수, 프로미스
  • ES7(2016) → prototype, **연산자
  • ES8(2017) → async/await, Object 정적 메서드
  • ES9(2018) → for await …of, async generator
  • ES10(2019) → Object.fromEntries, Array.prototype.flatMap
  • ES11(2020) → String. prototype. matchAll, BigInt, 옵셔널 체이닝 연산자 등

자바스크립트 성장의 역사

첫 자바스크립트는 웹 페이지의 보조기능을 수행하는 용도였고, 대부분의 로직이 웹 서버에서 실행되며 서버측에서 렌더링(Server Side Rendering)이 진행됨

Ajax

비동기(Asynchronous )방식으로 데이터를 교환할 수 있는 Ajax가 등장하며 렌더링을 Client측에서 직접 렌더링하기 시작했다

서버 측에서의 렌더링은 매번 데이터를 변경할 때마다 새로 페이지를 불러와 렌더링 해야하기에 성능상 문제가 있었고 사용자 입장에서도 좋지않은 경험이였다.

Ajax의 등장으로 변경되는 데이터만 특정하여 값을 변경해 부드러운 화면 전환 효과를 보게 되었다.

jQuery

jQuery는 자바스크립트의 까다롭고 복잡한 문제를 해결해주었고, 직관적인 jQuery로 인해 자바스크립트 환경이 더욱 개선되었다.

V8 자바스크립트 엔진

구글에서 개발한 V8엔진은 빠른 성능을 보여주었고, 데스크톱 애플리케이션과 유사한 사용자 경험을 제공할 수 있게 되었다.

이 이후 클라이언트 사이드 렌더링이 본격적으로 활성화되었고, 프론트엔드 영역이 주목받기 시작했다.

Node.js

브라우저에서만 동작하는 자바스크립트 엔진을 브라우저 이외의 환경에서도 동작할 수 있도록 브라우저에서 독립시킨 자바스크립트 실행 환경

Node.js가 생기며 프론트, 백 모두 자바스크립트를 사용해 개발할 수 있다는 동형성(동일한환경)이라는 *_장점이 있으며, *_비동기I/O, 단일스레드 이벤트 루프 기반으로 동작하기에 요청 처리성능이 좋으며 실시간으로 데이터를 처리하기 위해 I/O가 빈번하게 발생하는 SPA(Single Page Application)에 적합하다.

SPA 프레임워크

복잡해진 개발환경에서는 이전의 자바스크립트 환경에서는 수행하긴 하지만 변경에 유연해지며 CBD 방법론을 기반으로 하는 SPA(Single Page Application)가 대중화되었다.

SPA를 돕는 프레임워크/라이브러리로는 Angular, Reach, Vue.js, Svelte 등이 있다

자바스크립트와 ECMAScript

각 브라우저 제조사는 ECMAScript 사양을 준수해서 브라우저에 내장되는 자바스크립트 엔진을 구현한다.

자바스크립트는 큰 범주로 JavaScript내에 ECMAScript가 들어있다.

ECMAScript는 자바스크립트에서 구현할 때의 뼈대라고 생각해야 한다. 이 뼈대는 문법과 기본 기능을 정의하며 ECMAScript를 기반으로 브라우저에서 자바스크립트가 동작하는 엔진을 구현하여 자바스크립트 실행 환경을 제공한다.

자바스크립트는 브라우저 엔진을 통해 만들어져 실제 웹 페이지와 상호작용하기 위해 사용되는 프로그래밍 언어이다.

자바스크립트의 특징

  • 웹 브라우저에서 동작하는 유일한 프로그래밍 언어이다.
  • 개발자가 별도의 컴파일 작업을 수행하지 않는 인터프리터 언어이다.
  • 인터프리터 언어의 단점인 실행시간을 최적화하기 위해
    JIT(Just-In-Time) 컴파일 기술이 도입되어 자주 실행되는 코드를 컴파일해둔다
  • 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.

스터디 회고

자바스크립트가 ECMAScript를 아우른다는 것 추가설명

이 부분이 다음 주 주제와도 연결이 되다보니 이해가 중요한 부분이였는데, 제가 설명을 자세히 못 적었다고 생각이 드네요..!

다음번엔 이해하기 쉽도록 더 잘 정리해보겠습니다 ㅜㅜ

제가 이해할 때 도움됐던 부분을 조금 더 정보를 꺼내 부연 설명 드리자면, 크롬의 경우 우리가 자주 사용하는 확장프로그램을 예시로 들 수 있습니다.

확장프로그램은 ECMAScript 표준을 기반으로 작성되며, 브라우저 자체에서 제공하는 고유API와 모듈을 사용해 다른 기능과 상호작용합니다.

크롬 자체에서만 지원하는 API를 활용하기에 이는 JavaScript 라고 이해했었습니다!

  if (request.message === 'Tab updated') {
    console.log('Tab was updated');
  }
});

🤔 질문

자바스크립트에 대해 알게 된 좋은 글이었습니다! 감사합니다

올려주신 글 부분에서 Node.js 설명 중 궁금한 부분이 있습니다.
Node.js에서 단일 스레드 이벤트 루프 기반이라는데, 단일 스레드인 경우에는 여러 요청들이 몰리면 성능에 이슈가 생기는 것은 아닌가요?
단일 스레드라 요청 처리 성능이 좋다고 되어 있어서 궁금해져 여쭤봅니다!..

🖥️ 답변

저도 처음에 보고 당황해서 따로 검색을 했었는데, 명확히 이해하지 못했다 생각해 올리지는 않았었습니다..

제가 이해가 가능했던 부분까지 설명을 해보자면, 이벤트 루프에 대한 이해가 필요한데요.

간단하게 한 문장으로 표현하자면, 싱글스레드로 이벤트 루프 기능이 동작하고 있고, 상세 기능은 내부적으로 비동기요청들을 멀티스레드 처리생성해 로직 처리 후 콜백하는 형태입니다.

노드에서는 멀티스레드 처리하는 라이브러리를 libuv라고 부르며, 이 라이브러리가 스레드풀에 멀티스레드를 담은 후 요청들에 대한 처리를 진행 한다고 합니다.

때문에 싱글 스레드로 동작을 모니터링 후 동작 처리는 멀티스레드 라이브러리(libuv)에 비동기 요청으로 맡기는 식으로 동작한다고 합니다.

저도 완전한 이해를 기반으로 답변드리지 못하여 아쉽지만 생각보다 단번에 이해하기 어려워 큰 틀에서만 이해해둔 상태입니다..!

이는 이후 책 진도가 나가면 한번 더 깊게 다루도록 하겠습니다!!

반응형

+ Recent posts