본문 바로가기

Today I Learned/Javascript

변수는 무엇이고, 왜 필요할까? [Today I Learned - JS]

여러 날에 걸쳐 공부한 걸 한번에 정리해서 

글이 많이 길다...

 


변수 예시

var a = 10;

변수를 알아보기에 앞서,

컴퓨터는 어떻게 메모리에 값을 저장하고 계산하는가?

 

예를 들어 10 + 20 = 30 이라는 식을 계산하고 저장하려면?

 

👉컴퓨터는 CPU 를 사용해 연산하고, 메모리(memory)를 사용해 데이터를 기억한다.

 


01. 메모리(Memory)란?

=> 데이터를 저장할 수 있는 메모리 셀의 집합체

 

 

메모리의 형태

 

 

1. 메모리 셀 1개는 1바이트

  • 각 셀은 고유의 메모리 주소를 갖는다.
    • 메모리 주소 : 메모리 공간의 위치를 의미

2. 컴퓨터는 즉, 1바이트 단위로 데이터를 저장하거나 읽어들인다.

 

3. 컴퓨터는 모든 데이터를 2진수로 처리

  • 메모리에 저장되는 데이터는 데이터의 종류(숫자, 텍스트, 이미지, 동영상)에 상관없이 모두 2진수로 저장됨
    • 2진수 : 0과 1로 이루어진 숫자 조합

 

10 + 20 = 30 이라는 식이 있을 때
컴퓨터의 메모리는 10, 20 이라는 데이터를 저장해놓고 있어야 하고
결과값 30이 도출되면 30도 메모리에 저장해야 한다.

 


 

02. 메모리에 저장된 값 가져다 쓰는 법?

 

메모리에 저장된 값을...가져다...?

 

10 + 20 의 결과로 30이 도출되었다.

결과값 30을 가져다 쓰기 위해서는?

  • 단 한번만 사용하는 것은 문제가 없겠지만 ⇒ 만약 연산결과 30을 여러 번 재사용하고 싶다면
    • 메모리에 저장된 30을 메모리 주소를 통해 직접 접근하는 방법 외에는 없다!

 

하지만...메모리 주소는...안돼...!!!

하지만, 메모리 주소를 통해 직접 접근하는 방법은 치명적 오류를 발생시킴

시스템을 멈추게 하는 치명적인 오류 발생

  • 실수로 운영체제가 사용하고 있는 값을 변경하면 시스템을 멈추게 하는 치명적인 오류가 발생할 수 있기 때문에 ⇒ 자바스크립트 개발자의 직접적인 메모리 제어를 허용하지 않음

메모리 주소는 계속 변한다

  • 값이 저장될 메모리 주소는 코드가 실행될 때 메모리의 상황에 따라 임의로 결정
  • 동일한 컴퓨터에서 동일한 코드를 실행해도 코드가 실행될 때마다 값이 저장될 메모리 주소는 변경된다.
  • 코드가 실행되기 이전에는 값이 저장된 메모리 주소를 알 수 없으며, 알려주지도 않음

 

즉, 메모리 주소를 통해 값에 직접 접근하려는 시도는 올바른 방법이 아니다.

 

 


 

 

프로그래밍 언어는 기억하고 싶은 값을 메모리에 저장하고,

저장된 값을 읽어 들여 재사용하기 위해,

03. 변수라는 메커니즘을 제공한다

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

 

 

 

변수

  • 프로그래밍 언어에서 값을 저장하고 참조하는 매커니즘
  • 값의 위치를 가리치는 상징적인 이름
  • 변수는 프로그래밍 언어의 컴파일러 또는 인터프리터에 의해 값이 저장된 메모리 공간의 주소로 치환되어 실행된다.

즉, 개발자가 직접 메모리 주소를 통해 값을 저장하고 참조할 필요가 없고, 변수를 통해 안전하게 값에 접근할 수 있다.

 

 

변수에 여러 값을 저장하려면?

변수는 하나의 값을 저장하기 위한 매커니즘!

여러 개의 값을 저장하고 싶다면, 여러 개의 변수를 사용해야 한다.

  • 단, 배열이나 객체 같은 자료구조를 사용하면 관련이 있는 여러 개의 값을 그룹화해서 하나의 값처럼 사용할 수 있다.
변수에 값을 저장하는 것을 할당이라하고
var result = 10 + 20;

 

변수에 저장된 값을 읽어 들이는 것을 참조라고 한다.
result;

 

04. 식별자..?

 

식별자는 또 뭐죠..?

 

변수의 이름을 식별자 라고도 한다.

식별자 : 어떤 값을 구별해서 식별할 수 있는 고유한 이름

  • 식별자는 메모리 공간에 저장되어 있는 어떤 값을 구별해서 식별해낼 수 있어야 한다.
    • 이를 위해, 식별자는 어떤 값이 저장되어 있는 메모리 주소를 기억(저장)해야한다.
    • 식별자는 값이 저장되어 있는 메모리 주소와 매핑 관계를 맺으며, 이 매핑 정보도 메모리에 저장되어야 한다.
💡 이처럼, 식별자는 값이 아니라 메모리 주소를 기억하고 있다.

 

식별자는 변수 뿐만 아니라, 함수, 클래스 등의 이름은 모두 식별자다

식별자인 변수 이름으로는 메모리 상에 존재하는 변수 값을 식별할 수 있고

함수 이름으로는 메모리 상에 존재하는 함수를 식별할 수 있다. (자바스크립트에서 함수는 값이다.)

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

 

변수, 함수, 클래스 등의 이름과 같은 식별자는 네이밍 규칙을 준수해야 하며, 선언에 의해 자바스크립트 엔진에 식별자의 존재를 알린다.

 

 


05. 변수 선언

var  score;

변수를 선언한다!

변수 선언이란

  • 변수를 생성하는 것
  • 정확히 ⇒ 값을 저장하기 위한 메모리 공간을 확보하고 변수 이름과 확보된 메모리 공간의 주소를 연결해서 값을 저장할 수 있게 준비하는 것

변수 선언 시, 메모리의 형태

 

 

 


📍 잠깐! 이것만 짚고 넘어갈게요

 

변수를 선언할 때는 var, let, const 가 있다.

var 키워드는 여러 단점이 존재

  • 블록 레벨 스코프를 지원하지 않고 함수레벨 스코프를 지원한다는 것
    • 의도치 않게 전역 변수가 선언되어 심각한 부작용이 발생하기도 함
💡 let, const 는 var의 여러 단점을 보완하기 위해서 도입되었다

 

ES6 이전 사양에서는 var 키워드를 사용하고, ES6 이후 사양에서는 let, const 등이 사용되었을 것이다.

  • ES6는 기본적으로 하위 호환성을 유지하면서 ES5 기반위에 새로운 기능을 추가한 것
  • ES6 사양을 기준으로 자바스크립트를 학습한다 하더라도 ES5 사양을 잘 알아둘 필요가 있다.
    • ES5 를 잘 이해하고 있으면 ES6 를 더욱 빠르고 명확하게 이해할 수 있기 때문

변수의 선언과 초기화

var score;

위 변수 선언문은 다음과 같이 변수 이름을 등록하고 값을 저장할 메모리 공간을 확보한다.

 

변수 선언 시, 메모리의 형태

 

💡 변수를 선언한 이후, 아직 변수에 값을 할당하지 않았다.

 

 

따라서 변수 선언에 의해 확보된 메모리 공간은 비어 있을 것으로 생각할 수 있으나,

  • 확보된 메모리 공간에는 자바스크립트 엔진에 의해 undefined 라는 값이 암묵적으로 할당되어 초기화 된다.

 

만약 초기화 단계를 거치지 않으면?

  • 확보된 메모리 공간에는 이전에 다른 애플리케이션이 사용했던 값이 남아 있을 수 있다.
    • 이러한 값을 쓰레기 값이라 한다.
  • 즉, 메모리 공간을 확보 후, 값을 할당하지 않은 상태에서 곧바로 변수 값을 참조하면 쓰레기 값이 나올 수 있다.
  • 자바스크립트의 var 는 암묵적으로 초기화 하므로 이러한 위험으로부터 안전하다.

 

자바스크립트의 변수 선언 단계

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

 

 

변수를 사용하려면 반드시 선언이 필요하다.

  • 만약 선언하지 않은 식별자에 접근하면 ReferenceError(참조 에러)가 발생한다.
    • 식별자를 통해 값을 참조하려 했지만 자바스크립트 엔진이 등록된 식별자를 찾을 수 없을 때 발생하는 에러다

 


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

console.log(score) //undefined

var score; //변수 선언문

자바스크립트 코드는 인터프리터에 의해 한 줄씩 순차적으로 실행된다.

  • console.log(score)가 가장 먼저 실행되고 ⇒ 이 시점에는 아직 변수의 선언이 실행되지 않음
    • 참조 에러(ReferenceError) 가 발생해야 할 것 같지만
    • 참조 에러가 발생하지 않고 undefined 가 출력이 된다.
  • 그 다음 score 변수의 선언이 실행된다.

 

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

 

  • 자바스크립트 엔진은 소스코드를 한 줄씩 순차적으로 실행하기에 앞서 먼저 소스코드의 평가과정을 거치면서, 소스코드를 실행하기 위한 준비를 한다.
  • 소스코드의 평가 과정에서
    • 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문(변수 선언문, 한수 선언문)을 소스코드에서 찾아내 먼저 실행한다.
    • 소스코드 평가 과정이 끝나면 비로소 변수 선언을 포함한 모든 선언문을 제외하고 소스 코드를 한 줄씩 순차적으로 실행한다.
💡 즉, 자바스크립트 엔진은 변수 선언이 소스코드의 어디에 있든 상관없이 다른 코드보다 먼저 실행한다.

 

  • 따라서, 변수 선언이 소스코드의 어디에 위치하는지와 상관없이 어디서든지 변수를 참조할 수 있다.
다시 정리하자면, 변수 선언(선언단계, 초기화 단계)런타임(소스코드가 한 줄씩 순차적으로 실행되는 시점) 이전 단계에서 먼저 실행된다.

 

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

 

 


값의 할당

var score; //변수 선언

score = 80; //값의 할당
  • 변수 선언과 값의 할당을 2개의 문으로 나누어 표현한 것
var score = 80; //변수 선언과 값의 할당
  • 변수 선언과 값의 할당을 하나의 문으로 단축할 수 있다.

2개의 문으로 나누어 표현한 것과 하나의 문으로 단축하여 표현한 코드는 정확히 동일하게 동작한다.

  • 즉, 자바스크립트 엔진은 변수 선언과 값의 할당을 하나의 문으로 단축 표현해도 변수 선언과 값의 할당을 2개의 문으로 나누어서 각각 실행한다.

이때, 변수 선언과 값의 할당 실행 시점이 다르다는 것!

  • 변수 선언 ⇒ 런타임(소스 코드가 순차적으로 실행되는 시점) 이전에 먼저 실행
  • 값의 할당 ⇒ 소스코드가 순차적으로 실행되는 시점인 런타임에 실행된다.

 

console.log(score); //undefined

var score; // 1)변수 선언
score = 80; // 2)값의 할당

console.log(score); //80 
  • 1) 변수 선언 은 런타임 이전에 먼저 실행되고
  • 2) 값의 할당은 런타임에 실행된다.
  • 즉, score 변수에 값을 할당하는 시점에는 이미 변수 선언이 완료된 상태이고, undefined 가 초기화 되어있다.
    • 즉, score 변수에 값을 할당하면, score 변수의 값은 undefined 에서 새로 할당한 숫자 값 80으로 변경(재할당)된다.
console.log(score); //undefined

var score = 80; //위 2개의 문과 같은 의미

console.log(score); //80 
  • 변수의 선언과 값의 할당을 단축 표현해도 자바스크립트 엔진은 변수의 선언과 값을 할당을 2개의 문으로 나누어 각각 실행한다.
    • 따라서 변수에 undefined 가 할당되어 초기화 되는 것은 변함이 없다.

 

변수에 값을 할당할 때

  • 이전 값 undefined 가 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당 값 80을 새롭게 저장하는 것이 아니라
    • 새로운 메모리 공간을 확보하고 그 곳에 할당 값 80을 저장한다
    • score 변수의 이전 값인 undefined 는 어떤 변수도 값으로 갖고 있지 않다.
      • 즉, 어떤 식별자와도 연결되어 있지 않다.
      • 이것은 undefined 가 더 이상 필요하지 않다는 것을 의미.(단, 메모리에서 언제 해제될 지는 예측할 수 없다)
      • 이러한 불필요한 값은 가비지 콜렉터에 의해 메모리에서 자동 해제된다.
💡 가비지 콜렉터 : 어플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제하는 기능
  • 더 이상 사용되지 않는 메모리란, 간단히 말해 어떤 식별자도 참조하지 않는 메모리 공간을 의미
  • 자바스크립트는 가비지 콜렉터를 내장하고 있는 매니지드 언어
  • 가비지 콜렉터를 통해 메모리 누수를 방지한다.

 

 

문제 : 아래 예제의 실행 결과는 무엇일까?

console.log(score); //undefined

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

console.log(score); //80 

=> var score 는 호이스팅되어 변수 선언(선언과 초기화)가 되기 때문에 맨 위 console.log 는 undefined 를 출력하고,

score = 80; 은 런타임에서 실행되며 순차적으로 내려와 맨 아래 console.log 는 80 을 출력한다....?!!

 

 


값의 재할당

var score = 80;
score = 90;
  • var 키워드로 선언한 변수는 값을 재할당할 수 있다.
  • 재할당은 현재 변수에 저장된 값을 버리고 새로운 값을 저장하는 것.

 

💡 var 키워드로 선언한 변수는 선언과 동시에 undefined 로 초기화되기 때문에 엄밀히 말하면 변수에 처음으로 값을 할당하는 것도 사실은 재할당이다

재할당은 변수에 저장된 값을 다른 값으로 변경 ⇒ 그래서 변수라고 함(변할 수 있는 수)

만약 값을 재할당 할 수 없어서 변수에 저장된 값을 변경할 수 없다면 변수가 아니라 상수(constant)임

  • 상수는 한번 정해지면 변하지 않는 값
  • 즉, 상수는 한 번만 할당할 수 있는 변수

 

 


참고

서적 : 모던 자바스크립트 Deep Dive