자바스크립트 변수와 호이스팅

Duboo·2021년 12월 8일
0

자바스크립트

목록 보기
3/7
post-thumbnail

변수


이미지 출처

변수(Variable)는 값이 저장된 메모리 공간의 주소를 가리키는 식별자(identifier)입니다.

  • 값을 저장(할당)하고 저장된 값을 참조하기 위해 사용합니다.
  • 간단하게 그냥 "데이터를 담는 공간"이다. 라고 생각해도 됩니다.

사용 이유

  • 코드의 가독성을 높혀준다.
  • 코드의 해석을 도와준다.
  • 선언, 할당한 변수를 다시 사용함으로 인해 코드의 재활용성을 높혀준다.

사용 방법

선언

자바스크립트에게 변수를 사용한다는걸 알려주는 방법입니다.

변수를 선언하고 사용하기 위해서는 변수의 종류부터 알아야되는데
어떤 언어는 변수를 선언하기 위해서 int, char, double... 등을 알아야 합니다.

하지만 자바스크립트의 장점이자 단점은 그런거 필요없습니다.
어떤 종류의 변수가 오던지 var (혹은 let, const) 하나면 모든 값을 담을 수 있는 그릇이 준비가 되며 자바스크립트는 값을 담을 주소(메모리 공간)를 준비합니다.

  • 자바스크립트는 데이터 타입을 변수에 할당된 값의 타입에 의해 동적으로 변수의 타입이 결정됩니다.
    • 이를 우리는 동적 타이핑이라 합니다.
  • var 키워드는 Variable의 약자로 자바스크립트에서 변수 선언을 위해 사용되어 왔지만 ES6 이후 let, const가 나온 시점부터 사용하지 않는 것이 좋습니다. | 아래 설명
// 변수 선언
var number;
let number;
const number;

이렇게 변수의 이름을 선언하면 값을 담을 수 있는 그릇이 준비가 됩니다.

  • 정확히는 변수의 이름은 사용자가 사용하기 쉽도록 하기 위함이지 변수명(number)에 값이 담기는건 아닙니다.
  • 변수명(number)이 알고 있는건 단지 데이터를 저장할 수 있는 메모리 주소입니다.

할당

이제 자바스크립트에게 변수를 사용한다는걸 알려줬으니 값을 넣어줘도 됩니다.
이것을 할당이라 하는데 선언한 변수명에 값을 넣어주는 방법입니다.

  • 값을 메모리 주소(공간)에 저장한다고 생각하면 됩니다.
let name; // 변수 선언
name = 'js'; // 변수 할당
  • 이렇게 할당(저장)한 값을 사용하는(읽는) 것을 우리는 참조(reference)라고합니다

값의 종류

이제 변수에 값을 넣는 방법을 배웠으니 값의 종류에 대해서 알아보겠습니다.

값의 종류를 우리는 변수의 타입이라 말합니다.
이러한 타입은 크게 원시 타입(Primitive type)참조 타입(Object type)으로 나눌 수 있습니다.

  • 원시 자료형, 참조 자료형이라고 하기도 합니다.

원시 타입 | Primitive type

원시 타입의 경우 하나의 데이터를 담고 있습니다.

  • 문자열(String) "문자" 형태의 데이터
  • 숫자(Number) 숫자 형태의 데이터
  • 불리언(Booleaan) 참(true) 혹은 거짓(false)의 데이터
  • Undefined 빈 값
    • 해당 빈 값의 경우 변수를 만들어 놓았는데 아무 값도 넣지 않았을 때
  • Null 빈 값
    • 변수에 의도적으로 넣은 빈 값, 값을 지울 때 사용할 수 있습니다.
  • symbol

참조 타입 | Object type

원시 타입이 아닌 모든 값은 참조 타입입니다.

  • 원시 타입이 아닌 모든 값은 객체라는 말과 같은 말입니다.
    • 객체(Object)는 배열(Array), 함수(Function)를 포함합니다.

참조 타입은 원시 타입 데이터의 집합이라고 할 수 있습니다.

// Example
const obj = {name: 'JS', color: 'yellow'};
const arr = ['html', 'css', 'js'];
  • 객체(Object) 키(key)와 값(value)의 관계로 이루어져 있으며 보통 현실의 사물을 프로그래밍에 반영할 때 사용됩니다.
  • 배열(Array) 다양한 값을 하나의 그릇에 담고 있다 생각하면 됩니다.
  • 함수(Function) 어떠한 작업을 수행하기 위해 필요한 문(statement)들의 집합을 정의한 코드 블럭입니다.

선언 키워드

자바스크립트의 선언을 위해서 var, let, const를 사용한다고 했습니다.
이들의 차이를 간단하게 알아보겠습니다.

자바스크립트의 변수 선언은 선언초기화 단계를 거칩니다.

  • 앞선 설명에 "선언은 자바스크립트에게 변수를 사용한다고 알려준다."라고 했습니다.
  • 초기화는 선언한 주소에 값을 저장하기 위해 메모리 주소(공간)을 확보하고 암묵적으로 undefined를 할당해서 초기화시킵니다.
    • 쉽게 생각해서 값을 저장하기 위해 공간을 정리한다라고 생각할 수 있습니다.

그러면 변수를 선언하고 값을 할당해주지 않는다면 결과는 undefined가 나와야 합니다.

Example 😊

var test1;
let test2;

console.log(test1); // undefined
console.log(test2); // undefined

그런데 console.log를 이용해서 선언하기도 전에 값을 찍어보면 undefined가 나옵니다.
이것은 우리가 생각한대로 코드가 흘러가는 것에 의문을 가지게합니다.

Example 😨

console.log(test1); // undefined
console.log(test2); // Uncaught ReferenceError: test2 is not defined

var test1; 
let test2; 

let 키워드로 선언한 test2 변수를 보면 선언하지 않았기 때문에 에러가 나옵니다.
우리가 생각하는 코드는 이것이 정상이지만 var는 그렇지 않은걸 확인할 수 있습니다.

원인

원인은 자바스크립트 Parser가 함수를 실행하기 전에 해당 함수를 확인하며
이때 함수 안에 존재하는 모든 선언문에 대한 정보를 기억한 뒤에 실행시키기 때문입니다.

  • 런타임 환경이 아닌, 이전 단계에서 먼저 실행한다는 느낌입니다.

우리가 생각한 자바스크립트가 코드를 읽는 순서는 위부터 순차적으로 실행되길 기대하지만 그렇지 않습니다.

  • 쉽게 생각해서 변수 선언의 위치를 상관하지 않고 다른 코드보다 우선적으로 실행되게 합니다.
  • 이를 우리는 호이스팅(hoisting)이라 합니다.
    • 호이스팅 : 변수의 선언과 초기화가 동시에 이루어졌을 때, 자바스크립트 인터프리터가 변수의 선언을 함수의 맨 위로 이동시키는 동작

다른 예를 보겠습니다.

Example 😊

//함수 선언문
function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}

catName("호랑이");

// 결과: "제 고양이의 이름은 호랑이입니다"

Example 😨

//함수 선언문
catName("클로이");

function catName(name) {
  console.log("제 고양이의 이름은 " + name + "입니다");
}

//결과: "제 고양이의 이름은 클로이입니다"

함수 자체보다 앞서 함수를 호출했지만 코드가 작동합니다...

호이스팅

하지만 let, const로 선언한 변수는 호이스팅 시 변수를 초기화 하지 않습니다.

  • 정확하게는 let, const로 선언한 변수도 호이스팅에 해당됩니다. 하지만 undefined로 변수를 초기화하지는 않습니다.
  • 이는 우리가 생각한대로 코드가 순차적으로 돌아가는걸 기대할 수 있습니다.

조금 더 자세한 내용은 var 키워드로 선언한 변수와 달리 let, const로 선언한 변수를 선언하기 전에 참조하지 못하는 것은 호이스팅이 발생하지 않아서 접근하지 못하는 것이 아닌, 일시적 사각지대(TDZ - Temporal Dead Zone)이라는 공간 때문입니다.


다시 var, let, const의 차이를 살펴보겠습니다.

var

문제가 많은 키워드입니다.

특징

  • 변수 중복 선언이 가능하다.
    • 변수는 중복으로 선언해서는 안되지만 실수로 중복 선언을 하게 될 경우에도 var는 에러를 보내지 않습니다. 즉, 문제가 발생할 수 있습니다.
  • 함수 레벨 스코프이다.
    • 이는 스코프에 관한 얘기인데 var는 함수 레벨 스코프이기 때문에 함수 안에서만 살아있으며 외부에서는 참조할 수 없습니다. 지역 변수
    • 함수 외부에서 선언한 변수는 전역 변수로 어디서든 참조할 수 있습니다.
    • *var 키워드에 관한 함수 레벨 스코프 및 스코프에 관한 설명은 중요하기 때문에 따로 정리합니다.
  • 변수 선언을 하기 전에 변수를 참조하면 undefined로 초기화한다.
    • 위 Example의 좋지 못한 결과를 불러올 수 있습니다.

let

var의 문제를 해결하기 위해 ES6 이후 등장한 키워드입니다.

특징

  • 중복 선언이 불가능하다.

    • 당연히 중복으로 선언해서는 안됩니다. 하지만 실수로 중복 선언을 하게 될 경우 친절하게 에러를 보냅니다.
      • 재할당은 가능합니다. 다시말해 변수의 값을 변경할 수 있습니다.
  • 블럭 레벨 스코프를 가진다.

  • 선언과 초기화 단계가 분리되어 진행됩니다.

    • let 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점까지 변수를 참조할 수 없습니다.
      • 일시적 사각지대(TDZ - Temporal Dead Zone)이라는 공간에 존재하기 때문입니다.

const

var의 문제를 해결하기 위해 ES6 이후 등장한 키워드입니다.

특징

  • 중복 선언과 재할당 또한 불가능하다.

    • 정확하게는 원시 타입의 값을 변경할 수 없는 것이지 참조 타입의 값은 가능합니다. ex) obj, arr...
    • 이 부분을 더 정확하게 표현하자면 배열과 객체 자체를 바꿀 수 있는 게 아닌, 내부의 값들을 변경할 수 있다는 의미입니다. 이것이 가능한 이유는 내부의 값들은 변경될지 몰라도 해당 배열/객체가 위치하고 있는 주소는 변경되지 않기 때문입니다.
  • 선언과 초기화를 동시에 진행해야 한다.

  • 블럭 레벨 스코프를 가진다.


그러면 어떤 키워드를 사용해야하나

코드를 작성하는데 정답은 없겠지만 권장은 const입니다.
재할당이 반드시 필요한 변수만을 let 키워드를 사용하며, 그 외의 모든 키워드는 const를 사용하는 것이 잠재적인 실수를 만들지 않도록 도울것입니다.

profile
둡둡

0개의 댓글