Post

[모던 자바스크립트 Deep Dive]04장 변수

4.1 변수란 무엇인가? 왜 필요한가?

다음 연산을 실행하기 위해 자바스크립트는 아래와 같은 동작을 수행해야 한다.

1
10 + 20;
  • 코드를 계산(평가, evaluation)
  • 10, 20(리터럴, literal)과 +(연산자, operator) 의미 파악
  • 10 + 20(표현식, expression) 의미 해석(파싱, parsing)
  • 피연산자(operand)와 연산 결과 등을 메모리에 저장

컴퓨터는 어떻게 기억하는가

  • 메모리
    • 데이터를 저장할 수 있는 메모리 셀의 집합체
  • 메모리 셀
    • 하나의 크기는 1바이트(8비트)
    • 컴퓨터는 메모리 셀의 크기 단위로 데이터를 저장하고 읽음
    • 각 셀은 고유의 메모리 주소(메모리 공간의 위치)를 가짐
      • 0부터 메모리의 크기만큼 정수로 표현

자바스크립트는 직접적인 메모리 제어를 허용하지 않는다.

  • 메모리 주소를 통해 직접 값에 접근하는 것은 치명적 오류 가능성이 매우 높음
  • 메모리 주소는 코드가 실행될 때마다 임의로 결정되므로 코드를 실행하기 전에는 값이 저장될 메모리 주소를 알 수 없기 때문에 메모리 주소를 통해 값에 직접 접근할 수 없음

위 두 문제를 해결하기 위해 변수가 등장한다.

변수

  • 값의 위치를 가리키는 상징적인 이름
    • 하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름
  • 기억하고 싶은 값을 메모리에 저장, 저장된 값을 읽어 들여 재사용 용이
  • 할당(assignment): 변수에 값을 저장
  • 참조(reference): 변수에 저장된 값을 읽음

4.2 식별자

  • 어떤 값을 구별해서 식별할 수 있는 고유한 이름, 메모리 주소에 붙인 이름
  • 식별자는 어떤 값이 저장된 메모리 주소를 저장
    • 식별자는 값이 저장된 메모리 주소와 매핑 관계를 맺고 이 매칭 관계도 메모리에 저장됨
  • 변수, 함수, 클래스 등의 이름은 식별자(identifier)다.
  • 식별자는 네이밍 규칙을 준수해야 한다.
  • 선언(declaration)에 의해 존재를 알린다.

4.3 변수 선언

  • 변수 선언(variable declaration)은 변수 생성이다.
    • 변수를 사용하려면 반드시 선언해야 한다.
    • 변수 선언시에는 var, let, const 키워드를 사용한다.
      • 키워드: 자바스크립트 엔진이 수행할 동작을 규정한 명령어
  • 변수 선언 과정
    1. 선언 단계: 변수 이름을 등록해 변수의 존재를 자바스크립트 엔진에게 알림
    2. 초기화 단계: 값을 저장하기 위한 메모리 공간 확보(allocate)
      • 초기화: 값이 할당되기 전에는 자바스크립트 엔진에 의해 undefined라는 값이 할당되어 초기화 진행
      • 메모리 공간은 확보가 되면 해제(release)되기 전까지는 누구도 사용할 수 없는 안전한 공간이다.
    3. 변수 이름과 확보된 메모리 공간 주소를 연결(name binding)

초기화 단계를 거치지 않는다면

이전에 존재하던 값이 메모리 공간에 남아 있을 수 있어 이를 참조하면 쓰레기 값(garbage value)가 나올 수 있다.

선언하지 않은 식별자에 접근한다면

ReferenceError 발생

실행 컨텍스트(execution context)

  • 변수 이름이 등록되는 곳
  • 자바스크립트 엔진이 소스코드를 평가하고 실행하기 위한 환경 제공
  • 코드의 실행 결과를 관리
  • 식별자는 실행 컨텍스트에 등록되며 자바스크립트 엔진은 이를 통해 식별자와 스코프 관리
    • 변수 이름과 변수 값은 키/값 형식의 객체로 등록되어 관리

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

1
2
3
console.log(score); // undefined, 즉 ReferenceError 발생 X

var score; // 변수 선언

변수 선언의 실행 시점

  • 런타임이 아닌 그 이전 단계
    • 런타임: 소스 코드가 한 줄씩 순차적으로 실행되는 시점

변수 선언이 런타임 이전에 실행되는 이유

  • 자바스크립트 엔진이 소스코드의 평가 과정을 거친 뒤 소스코드를 한 줄씩 순차적으로 실행하기 때문
  • 소스코드의 평과 과정: 자바스크립트 엔진이 모든 선언문을 소스코드에서 찾아내 먼저 실행
    • 선언문: 변수 선언문, 함수 선언문, 클래스 선언문 등
    • 소스코드의 평과 과정 이후 선언문을 제외한 소스코드를 한 줄씩 순차적 실행

변수 호이스팅

  • 위와 같이 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징

4.5 값의 할당

1
2
var score; // 변수 선언
score = 80; // 값의 할당
1
var score = 80; // 변수 선언과 값의 할당
  • 자바스크립트 엔진은 변수 선언과 값의 할당(assignment)을 하나의 문(statement)로 단축 표현해도 각각을 2개의 문으로 나누어 각각 실행

    • 변수 선언: 런타임 이전에 실행
    • 값의 할당: 런타임에 실행
    1
    2
    3
    4
    5
    
    console.log(score); // undefined
    
    var score = 80; // 변수 선언과 값의 할당
    
    console.log(score); // 80
    
  • 변수에 값을 할당하는건 이전 값이 저장되어 있던 메모리 공간을 지우는것이 아닌, 새로운 메모리 공간을 확보함으로써 이루어진다.

4.6 값의 재할당

  • 재할당: 이미 값이 할당되어 있는 변수에 새로운 값을 할당
  • 상수: 값을 재할당 할 수 없는, 단 한 번만 값을 할당할 수 있는 변수
    • const 키워드로 선언한 변수는 재할당이 금지되어 상수를 표현 할 수 있다.

메모리 공간에 남겨진 값은 어떻게 되는가

  • 변수에 값을 재할당하면 특정 메모리 공간에 저장되어 있던 원래의 값은 변수를 잃는다.
  • 메모리 공간의 값이 어떤 식별자와도 연결되어있지 않다면 가비지 콜렉터에 의해 메모리에서 자동 해제된다.
    • 해제되는 시점은 예측할 수 없다.

가비지 콜렉터

  • 애플리케이션이 할당(allocate)한 메모리 공간을 주기적으로 검사해 더 이상 사용하지 않는 메모리를 해제(release)하는 기능
    • 더 이상 사용하지 않는 메모리: 어떤 식별자도 참조하지 않는 메모리 공간
  • 이를 통해 메모리 누수(memory leak)를 방지
  • 자바스크립트는 가비지 콜렉터를 내장한 매니지드 언어이다.

언매니지드언어와 매니지드 언어

  • 언매니지드 언어(unmanaged language)
    • C 언어 등
    • malloc()free() 같은 저수준(low-level) 메모리 제어 기능 제공
      • 이를 통해 개발자가 명시적으로 메모리를 할당하고 해제
    • 메모리 제어를 개발자가 주도
      • 개발자 역량에 따라 최적의 성능 확도 또는 치명적 오류 생산
  • 매니지드 언어(managed language)
    • 자바스크립트 등
    • 언어 차원에서 메모리 할당 및 해제를 위한 관리 담당
      • 개발자의 직접적 메모리 제어 허용 안함
      • 개발자의 역량에 크게 의존하지 않아 일정한 생산성 확보 가능
      • 하지만 성능에 어느정도 손실이 존재
    • 사용하지 않는 메모리 해제는 가비지 콜렉터가 수행
      • 이 또한 개발자가 관여 못함

4.7 식별자 네이밍 규칙

  • 식별자(identifier): 어떤 값을 구별해서 식별해낼 수 있는 고유한 이름

식별자 네이밍 규칙

  • 식별자는 특수문자를 제외한 문자, 숫자, 언더스코어, 달러 기호를 쓸 수 있다.
  • 식별자는 숫자로 시작할 수 없다.
  • 예약어는 식별자로 사용할 수 없다.

변수 선언시 비권장 사항

  • 변수는 쉼표로 구분해 하나의 문에서 여러 개를 선언할 수 있지만 가독성이 나쁘므로 권장하지 않는다.
  • ES5부터 한국어나 일본어 식별자도 사용할 수 있지만 권장하지 않는다.
  • 명확하지 않은 변수 이름은 권장하지 않는다.

네이밍 컨벤션

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 카멜 케이스 (camelCase)
var firstName;

// 스네이크 케이스 (snake_case)
var first_name;

// 파스칼 케이스 (PascalCase)
var FirstName;

// 헝가리언 케이스 (typeHungarianCase)
var strFirstName; // type + identifier

// DOM 노드
var $elem = document.getElementById("myId");

// RxJS 옵저버블
var observable$ = fromEvent(document, "click");

식별자에는 일반적으로 다음 컨벤션을 사용한다.

  • 카멜 케이스
    • 변수의 이름
    • 함수의 이름
  • 파스칼 케이스
    • 생성자 함수
    • 클래스의 이름
This post is licensed under CC BY 4.0 by the author.