[JavaScript] const, let, var 차이점 + 호이스팅(Hoisting)


첫번째 차이점 - 접근 범위

var는 function level scope 즉, 함수 단위 범위를 가진다.

let 과 const는 block level scope 즉, 중괄호{ } 단위 범위를 가진다.




function level scope란 

선언된 함수의 { } 중괄호 안에서 작성된 변수와 함수는 함수 블록 내부에서만 참조가 가능하다.

선언된 함수 블록을 제외한 if 조건문, for 와 같은 반복문 등의 블록 내부에서 선언된 변수 또는 함수는 전역변수이면서 전역함수이다.

function person() {
var name1 = "lee";
let name2 = "kim";
}

console.log(name1); // ReferenceError: name1 is not defined => var는 함수 레벨 스코프 이므로 접근 불가
console.log(name2); // ReferenceError: name2 is not defined => let은 블록레벨 스코프 이므로 접근 불가

{
var fruit = "apple";

console.log(fruit); // apple
}

console.log(fruit); // apple => 함수 레벨 스코프이므로 var로 선언한 변수는 전역변수가 된다.

if (true) {
var name1 = "lee";
let name2 = "kim";
}

console.log(name1); // lee => var는 함수 레벨 스코프이므로 참조가능(전역변수)
console.log(name2); // ReferenceError: name2 is not defined => let은 블록레벨 스코프 이므로 접근 불가


function level scope 는 함수의 코드 블록만을 스코프로 인정한다.

함수 외부에서 생성한 변수는 모두 전역 변수이다. 



block level scope란

{ } 중괄호 안에서의 let 또는 const로 선언한 변수와 함수 표현식은 블록 안에서만 참조할 수 있는 범위를 가진다. 

중괄호 외부에서 중괄호 내부에 let과 const로 선언한 변수, 함수에 대한 참조가 불가능하다.

if 조건문이나 for와 같은 반복문 등에서의 중괄호 내부에 let 또는 const 로 선언된 변수와 함수는 block level scope 이므로 블록 외부에서 참조가 불가능하다.

{
let fruit = "apple";
const NUMBER = "010-0000-0000";

console.log(fruit); // apple
}

console.log(fruit); // ReferenceError: fruit is not defined

if (true) {
let name = () => {
console.log("lee");
};
}

name(); // ReferenceError: name is not defined



두번째 차이점 - 호이스팅(Hoisting)


호이스팅(Hoisting)이란 var 또는 function으로 선언된 선언문을 해당 스코프의 선두로 옮긴것처럼 동작하는 특성을 말한다.

console.log(hoist); //undefined

var hoist = 100;

console.log(notHoist); //ReferenceError: Cannot access 'notHoist' before initialization

let notHoist = 200;



var는 선언하기 이전에 사용할 수 있지만 let, const는 선언하기 이전에 사용할 수 없다.

컴퓨터는 코드를 해석 할 때 왼쪽에서 오른쪽으로, 위에서 아래로 해석을 해 나간다.

그렇다면 위에서 부터 순서대로 코드가 실행되는데 아직 hoist 에 100이라는 숫자가 할당되지 않았는데 변수를 호출하여 값을 출력하는것을 볼 수 있다. 하지만 아직 hoist 변수에 100이 할당되지 않았기 때문에 undefined를 출력하게 된다. 이러한 특성이 호이스팅(Hoisting)이다.

반면에, let을 사용하여 변수를 선언한 notHoist 변수는 선언이전에 호출되었다고 에러가 반환되는것을 확인할 수 있다.


요약:

var와 함수 선언문은 호이스팅(Hositing) 현상 발생

let, const와 함수 표현식은 호이스팅 현상 발생X



3번째 차이점 - 재선언


var는 변수를 선언한 후 동일한 변수와 함수를 다시 아래에서 재 선언 가능

var fruit = 'apple';
console.log(fruit); //apple

var fruit = 'banana';
console.log(fruit); //banana

function apple() {
console.log(1);
}

function apple() {
console.log(2);
}

apple(); //2 가장 마지막에 선언된 함수가 출력된다.



반면에 let, const는 동일한 명칭의 변수 재 선언이 불가하다.

let fruit = 'apple';
console.log(fruit); //apple

let fruit = 'banana'; // SyntaxError: Identifier 'fruit' has already been declared
console.log(fruit);


const getApple = () => {
console.log(1);
};

const getApple = () => {
console.log(2);
};

apple(); //SyntaxError: Identifier 'getApple' has already been declared







추가적으로 const 와 let 의 비교



let은 mutable 하다. (
값 재할당이 가능하다.)

const는 immutable 하다. (값 재할당이 불가능하다.)



const는 상수를 선언할 때 사용된다. const는 값을 재할당 할 수 없지만 배열(array)과 객체(object)의 값을 수정(추가, 삭제)하는 것은 가능하다.


//1번
const num1 = [1, 2, 3, 4, 5];
num1 = [6, 7, 8, 9, 10];

console.log(num1); //error

//2번
let num2 = [1, 2, 3, 4, 5];
num2 = [11, 12, 13, 14, 15];

console.log(num2); //[11, 12, 13, 14, 15]

//3번
const list = ['apple', 'banana', 'strawberry'];
list.push('mango');

console.log(list); // ["apple", "banana", "strawberry", "mango"]



1번의 경우 const를 사용하고 있고 값을 재할당할 경우 error를 반환한다.

2번의 경우 let은 값을 재할당받아 [11, 12, 13, 14, 15]를 반환한다. 
(배열은 원시데이터 타입이 아닌 객체이기 때문에 값을 참조하는데 객체에 새로운 객체를 할당하면 참조를 더이상하지않고 새롭게 할당된 객체 데이터가 그 변수의 값이 된다.)

3번의 경우 const를 사용하여 객체의 프로퍼티를 정의하고있지만 push 메소드를 사용하여 원래의 프로퍼티값을 수정하여 ["apple", "banana", "strawberry", "mango"]를 반환한다.

즉, const를 사용하더라도 배열과 객체의 값을 변경하는것(추가, 삭제)은 가능하다.



마지막으로 es6부터는 코드를 잘 작성하기위해서 3가지 정도를 유념하자.

1. let 과 const를 기본으로 사용한다. 되도록 immutable한 const를 사용하도록 한다.

2. 재할당이 필요한 경우에 한정해서 let을 사용한다.

3. var는 사용하지 않는다.



댓글