var, let, const의 차이

Keun·2022년 6월 18일
0

알아보기전에....미안해요다들...

이건 내가 예전부터 C언어 배울때부터, 자바, 파이썬 그리고 자바스크립트를 대충 거치고 배우면서 너무 당연시하였지만, 자바스크립트를 요즘 리액트 개발자가 되려고 배우면서 건드리게된다.

분명 변수의 선언과 동시에 메모리에서 일어나는 일에 대해서 배웠겠지만, 그만큼 항상 코딩에만 집중할뿐, 개념에는 집중하지 못했다. 이제와서 좀 무슨일이 일어나는지 알게되는 것 같아 스스로에게 반성한다. 모르고 쓰다니...그래놓고 연구프로젝트라던가, 간단한 팀프로젝트라던가 등등 할때 모르고 썼다니...괜히 부끄럽고 미안하다.

이 정리는, 자바스크립트 공식문서와 한 블로거님의 엄청난 글을 기반으로 했다

https://www.howdy-mj.me/javascript/var-let-const/

열심히 공부할게요감사해요!!

변수

이 그림 보자마자 한번에 알아들었다. 왜냐하면, 많이써봤으니까. 그런데 저 사실을 잠시 잊고있었다. 메모리에 내가 선언한 변수가 들어간다는것. 와...기분 묘했다.
이 그림의 상황을 코딩해보면,

const myNumber = 23;
// 변수명(식별자): myNumber
// 해당 값의 위치(메모리 주소): 0012CCGWH80
// 변수 값(저장된 값): 23

이거다. 이거 한줄 딱 치면 변수명이 저런 애가 메모리 주소가 저것이고, 저장된 값은 저것이다.

그림과 같이 하는 것을 할당(assignment)라고 하고, 여기서 그림에 저장된 값들을 불러들여오는 것을 참조(reference)라고 한다. 그리고 const myNumber이런것을 선언(declaration)이라고 한다~

변수선언

나는 프로젝트하면서 const만 썼다. 쓴 이유는, 값이 바뀌거나 그 값들이 다른 곳에서 쓰이는 것을 막기 위해서다. 즉, 재할당, 재선언등을 방지하기 위해서이다. 그래서 var과 let에 대해 좀 가물가물해졌다. 대신 그것은 안다. var이라는 친구는 정말 웃기다는 것을. 아무튼 머릿속에 꼬깃꼬깃한 개념을 펴줘야 하니까 차근차근 해보자고~

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

var root
console.log(root) // undefined

값 자체를 아무것도 일단 안넣어 줬으니까, 일단 undefined를 메모리 공간에 할당한다.

console.log(root) //undefined
var root

반대로 이렇게 해도 undefined나온다.

자바스크립트 쓰면서 제일 놀랐던 것중 하나.
"이게 된다고? 왜?"

자바스크립트 엔진은 소스코드를 한줄 씩 순차적으로 실행하기에 앞서, 변수 선언을 포함한 모든 선언문을 찾아내 먼저 실행한다. 즉 변수선언이 어디에 있든 상관없이, 먼저 찾아내서, 다른 코드보다 먼저 실행되는 특징 -> 호이스팅(hoisting)이라고 한다. var, let, const, function, class등 선언하는 모든것들은 먼저 호이스팅 된다.

변수 할당

var root //변수선언
root = "bright" //값 할당

var root = "bright" // 변수 선언과 할당

할당을 이렇게 하면 되는 것이고,

console.log(root) // undefined

var root = "bright"
console.log(root)//bright

실행 위치에 따라 아웃풋이 다르고~

console.log(root) // "bright"
 root="pirate"
 console.log(root)// "pirate"

이렇게 되는것을 재할당이라고 한다.
그런데! 변경이 안된다면 상수(constant)라고 한다. *const!

함수 호이스팅!

// 1. 함수 선언문
// 함수 이름 생략 불가능
function add(x, y) {
  return x + y
}

// 2. 함수 표현식
// 함수 이름 생략 가능
var add = function(x, y) {
  return x + y
}
// 함수 이름 작성 시,
// var add = function plus(x, y) {
//   return x + y
// }

// 3. Function 생성자 함수
var add = new Function('x', 'y', 'return x+ y')

// 4. 화살표 함수
var add = (x, y) => x + y

이러한 방법으로 함수를 선언하고 표현할 수 있다. 정말 다양하다...오...생각보다 많네..나는 개인적으로 1번이랑 4번 많이쓰고 4번이 뭔가 화살표도 보이고 이쁘다.

호이스팅 결과:

// 함수 참조
console.dir(add) // output: f add(x, y)
console.dir(sub) // output: undefined

// 함수 호출
console.log(add(2, 5)) // output: 7
console.log(sub(2, 5)) // output: Uncaught TypeError: sub is not a function

// 함수 선언문
function add(x, y) {
  return x + y
}

// 함수 표현식
var sub = function(x, y) {
  return x + y
}

여기서 함수 선언문만이 호이스팅 가능이고 함수 표현식은 undefined가 나오는 것을 볼 수 있다.

스코프

이름만 어렵지 사실 진짜 별 것 없는 개념이다. 스코프는 한글로하면 그냥 영역이라는 뜻이다. 쉽게 말하면, 함수 안에서 변수가 선언되면 그 변수는 함수 안에서만 활동 가능하다. 반면에 함수 밖, 즉 그냥 맨 화면에다가 선언하면 함수 안에서도 가능하고 이곳저곳 가능하다. 그럴때 전자를 지역변수, 후자를 전역변수라한다.

지역레벨 스코프를 if, for while, try/catch등에서만 가능한 것을 블록 레벨 스코프라한다.
var이 참 오픈마인드다.

var a = 1

if (true) {
  var a = 5
}

console.log(a) // output: 5

항상 내 생각 밖의 무엇인가를 만드는 것 같다 ㅋㅋㅋㅋㅋ 진짜 이건 상상도 못했다.

함수가 아닌 곳에서 var 선언하고 전역변수 취급되다가, 변수 중복 선언되면 다시 변경된 값으로 변해버린다.
따라서 오로지 함수 코드 블록만을 지역스코프로 인정하는 var 대신, 블록레벨 스코프를 지원하는 const와 let을 사용 하는 것을 권장한다고 한다.

최종 정리: 그러면 var | let | const 차이

var 키워드는 문제투성이

  • 변수 중복 선언 가능
  • 함수 레벨 스코프로 인해 함수 외부에서 선언한 변수는 모두 전역 변수로 된다.
  • 변수 선언문 이전에 변수를 참조하면 언제나 undefined를 반환한다.

변수 중복 선언 불가.

(1) let
변수 중복 선언 불가 / 재할당 가능.

let name = 'kmj'
console.log(name) // output: kmj

let name = 'howdy' // output: Uncaught SyntaxError: Identifier 'name' has already been declared

name = 'howdy'
console.log(name) // output: howdy

(2) const
반드시 선언과 초기화를 동시에 진행해줘야해.

const name; // output: Uncaught SyntaxError: Missing initializer in const declaration
const name = "what"

알고보면 다른 언어에서는 정상적인 모습이라고 난 알 고 있 다...

재선언 재할당 불가하고, 원시값 불가능하지만 객체만 가능.

// 원시값의 재할당
const name = 'what'
name = 'howdy' // output: Uncaught TypeError: Assignment to constant variable.

// 객체의 재할당
const name = {
  eng: 'what',
}
name.eng = 'howdy'

console.log(name) // output: { eng: "howdy" }

블록레벨 스코프

let 과 const는 함수레벨스코프만 좋아하는 var과 다르게 블록레벨 스코프를 따른다.

let a = 1

if (true) {
  let a = 5
}

console.log(a) // output: 1

const도 이와같이 움직인다. var보다 훨씬 낫다.

변수 호이스팅

(1) let
let 키워드로 선언한 변수는 선언 단계와 초기화 단계가 분리되어 진행된다. 즉, 런타임 이전에 자바스크립트 엔진에 의해 선언 단계가 먼저 실행되지만, 초기화 단계가 실행되지 않았을 때 해당 변수에 접근하려고 하면 참조 에러가 뜬다.

console.log(name) // output: Uncaught ReferenceError: name is not defined

let name = 'wow'

따라서 let 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점까지 변수를 참조할 수 없는 일시적 사각지대(Temporal Dead Zone: TDZ) 구간에 존재한다.

(2) const
앞에서 말했듯이 선언이랑 초기화 둘다 동시에 진행된다. 당연히 얘도 똑같다.

console.log(name) // output: Uncaught ReferenceError: name is not defined

let name = 'wow'

let 키워드로 선언한 경우, 런타임 이전에 선언이 되어 자바스크립트 엔진에 이미 존재하지만 초기화가 되지 않았기 때문에 name is not defined라는 문구가 떴다. 하지만 const 키워드로 선언한 경우, 선언과 초기화가 동시에 이루어져야 하지만 런타임 이전에는 실행될 수 없다. 따라서 초기화가 진행되지 않은 상태이기 때문에 Cannot access 'name' before initialization 에러 문구가 뜬다.

참고: 모던 자바스크립트 Deep Dive, 이웅모 (2020)

0개의 댓글