var, let, const의 차이

최경열·2021년 9월 22일
0
post-thumbnail

var로 변수를 선언이 가능하면서도 왜 let, const가 나왔을까?
이유를 정확히 알기 위해서 우선 변수의 선언 및 할당, 호이스팅, 스코프를 알아보자


변수

변수는 하나의 값을 저장하기 위해서 확보한 메모리 공간 즉 주소를 이름으로 식별하기 위해 붙힌 이름이다.

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

자바스크립트는 매니지드언어(managed language)라서 개발자가 직접 메모리를 제어하기 힘들다.
따라서 개발자는 직접 메모리 주소를 통해 값을 저장, 참조 할 필요가 없고 변수를 통해 안전하게 메모리에 값에 접근이 가능하다.

위 변수명인 myNumber은 변수의 값인 23이 아니라 메모리 주소(0012CCGWH80)를 기억하고 있다.
변수명을 사용하면, 변수명과 매핑된 메모리 주소를 통해서 저장된 값(23)을 반환한다.

이처럼 변수에 값을 저장하는것을 할당(assignment), 변수에 저장된 값을 읽어들이는 것을 참조(reference), 변수명을 자바스크립트 엔진에 알리는 것을 선언(declaration)이라 한다.


변수선언

변수의 선언은 ES6에서 const, let이 추가되어 var, let, const 로 할수 있다.
자바스크립트에서 변수선언은 선언 => 초기화 단계를 거쳐 수행된다.

var cky
console.log(cky) // output: undefined

var 를 이용한 변수의 선언은 선언,초기화 단계가 동시에 진행되며, cky에 암묵적으로 undefined 를 할당해서 초기화 한다.
그런데 반대로, console.log를 먼저 찍어도 반환값이 underfined 가 나온다.

console.log(cky) // output: undefined
var cky

어떻게 변수 선언을 하지 도 않았는데 underfined 가 console에 나올수 있는가?
그 해답은 변수 선언은 런타임에서 되는것이 아니고 그 이전단계에서 먼저 실행되기 때문이다.
자바스크립트엔진은 소스코드를 한줄씩 실행시키기 전에, 변수 선언을 포함한 모든 선언문(ex 변수선언문, 함수 선언문 등)을 찾아내 먼저 실행한다. 즉 변수 선언의 위치에 상관없이 다른 코드들보다 먼저 실행이 되는데 이러한 특징은 호이스팅(hoisting)이라 한다.


변수할당

변수의 값을 할당시에는 =를 사용한다.

var cky // 변수 선언
cky = 'hello' // 값의 할당

var cky = 'hello' // 변수 선언과 할당

변수 선언과 할당은 하나의문(statement)로 단축표현 할수 있지만, 두개의 실행 시점은 다르다.
변수 선언은 호이스팅되어 런타임 이전에 실행이 되지만, 값의 할당은 소스코드가 순차적으로 실행되는 런타임에 실행이 된다. 즉 두번째 변수 선언과 할당은 호이스팅되어도 값의 할당은 런타임에 실행되므로 맨 첫줄이 console라면 underfined 가 출력이 된다.

console.log(cky) // output: undefined

var cky = 'hello'
console.log(cky) // output: hello

함수 호이스팅

// 함수 참조
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
}

함수선언문 add경우 런타임 이전에 실행되어 함수 자체를 호이스팅 시킬수 있다. 즉 값이 나올 수 있다.
함수 표현식은 위 변수 값 할당 호이스팅 처럼 런타임 이전에 해당값을 underfined 로 초기화 시키고, 런타임때 해당 함수의 표현식이 할당 되어 그때 객체가 되어 값이 나올수 있다.
즉 함수선언문은 변수선언과 마찬가지로 런타임전 호이스팅되어 값이 나올수가 있으며,
함수 표현식은 런타임때 값이 나올수 가 있다.


스코프

식별자의 유효범위를 뜻하며, 선언된 위치에 따라 유효범위가 달라진다.
전역에 선언된 변수는 전역 스코프, 지역에 선언된 변수는 지역스코프를 갖는다.

전역 변수는 어디든지 참조가 가능하며, 지역변수는 자신의 지역 스코프와 그 하위 지역 스코프에서 유효하다.

자바스크립트에서 모든 코드블록이(ex if, for, while, try/catch 등) 지역 스코프를 만들며, 이런 특성을 블록레벨스코프라고 한다. 그러나 var로 선언된 변수는 오로지 함수 코드블록만을 지역 스코프로 인정한다. 이를 함수레벨스코프라고 한다.

var a = 1

if (true) {
  var a = 5
}

console.log(a) // output: 5

위 코드를 보면 함수가 아닌 if에서 var을 이용해 a를 선언했기에 이는 전역변수로 취급한다. 이는
기존에 있는 a 변수가 중복 선언 되면서, 하단 console에서도 출력값이 5로 바뀐것을 통해 확인할수 있다.

위 예저는 코드가 짧아서 문제발생여부와 위치가 파악이 가능하나, 실무에서는 그렇지 않다. 전역변수로 인해 재할당이 발생하거나, 전역 스코프를 공유하기 때문에 어딘가 동일한 이름의 변수가 있다면 예상치 못한 변수의 값이 변경되는 결과를 가지고 올수 있다. 따라서 오로지 함수코드블록만을 지역 스코프로 인정하는 var 대신, 블록레벨스코프를 지원하는 cosnt , let 을 사용하는것을 권장하는 것이다.


var, let , const 차이

앞에서 작성한 var 의 문제점은 크게 3가지가 존재한다.

변수의 중복선언이 가능하다

변수 선언문 이전에 변수를 참조시 언제나 undefined를 반환

함수레벨스코프이다.

let, const 는 위 3가지 문제를 해결하였다.

1. 변수 중복 선언 불가

let : 변수 중복 선언불가, 재할당은 가능

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

let name = 'abcd' // output: Uncaught SyntaxError: Identifier 'name' has already been declared
//중복 선언 불가

name = 'abcd'
console.log(name) // output: abcd, 재할당은 가능

const : 변수 중복 선언불가, 재할당 불가(원시값은 불가능, 단 객체는 가능)

const name = 'cky'
name = 'abcd' // output: Uncaught TypeError: Assignment to constant variable.
// 원시값 재할당 불가

const name = {
  eng: 'cky',
}
name.eng = 'abcd'

console.log(name) // output: { eng: "abcd" }
// 객체의 재할당은 가능

추가로 letconst 가 다른점 중 하나는, 반드시 선언과 초기화를 동시에 진행해야 한다.

const name; // output: Uncaught SyntaxError: Missing initializer in const declaration
const name = 'cky'

2. 변수 호이스팅

let : 선언단계와 초기화 단계가 분리되어 진행
const : 선언단계와 초기화 단계가 동시에 진행

3. 블록레벨스코프

모두 코드블록 (ex if, for, while, try/catch 등)을 지역스코프로 인정하는 블록레벨스코프를 따른다.


정리

변수의 스코프는 가능한 간략히, 좁게 만드는것을 권장하며 변수의 값은 쉽게 파악하기 위해서는 var보다는 let, const 를 사용하는것이 좋다. 또한 변수의 값이 상수라면 let보다는 const 를 사용하는것이 보다 안전하다.

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

profile
숲을보는 개발자

0개의 댓글