[클린코드 JS] 1장. 변수 다루기

JINJIN·2023년 2월 12일
1

클린코드 JS

목록 보기
2/3

해당 시리즈는 온라인 강의 사이트 '유데미'에서 클린코드 자바스크립트 강좌를 시청하고 작성하는 글입니다.


📌 var를 지양하자

JavaScript에서 변수를 선언할 수 있는 키워드는 var, let, const 이렇게 3가지 방법이 있습니다. 이 중에서 letconstES2015 버전에 처음 등장한 친구들이어서 어쩔 수 없이 그 전까지는 var 예약어를 통해서만 변수를 만들 수 있었습니다.

이렇듯 letconstvar의 단점을 보완하고 대체하기 위해 나온 키워드입니다. 하지만 예전에 작성된 코드들이나 습관적으로 작성된 코드들을 살펴보면 아직도 var은 종종 보이기도 합니다!

그럼 var 그리고 let, const의 차이점은 무엇일까요?

우선 var은 함수 단위 스코프를 가지고, letconst는 블록 단위 스코프를 가진다는 점이 가장 큰 차이점이라고 말할 수 있습니다.

스코프(scope)는 변수에 접근할 수 있는 범위를 말합니다.
그리고 스코프는 크게 전역 스코프와 지역 스코프로 나눌 수 있습니다.
전역 스코프(global)는 어디에서든 해당 변수에 접근 가능한 걸 의미합니다. (전역변수)
지역 스코프(local)의 경우, 한정적인 범위에서 해당 변수에 접근이 가능합니다. (지역변수)
그리고 위에서 설명한 함수 스코프, 블록 스코프는 모두 지역 스코프에 해당합니다.

함수 스코프, 블록 스코프의 차이점

  • 함수 스코프 var
    • 함수가 선언되면 하나의 스코프(접근 범위)가 발생하는데 이걸 함수 스코프라고 합니다.
    • 함수 스코프는 함수에서 선언한 변수는 해당 함수 내에서만 접근 가능하다는 걸 의미합니다.
    • 아래 예시처럼 함수 외부에서 A를 호출하면 undefined 에러가 뜹니다.
      function Test() {
      	var A = '1'; // 함수 내부에서 선언
      }
      console.log(A); // Uncaught ReferenceError: A is not defined

    • 만약 변수가 함수 내부에 선언된 것이 아니면 이 변수의 스코프는 전역 스코프(global)이므로 어디에서든 접근이 가능합니다.
      var A = '1';
      console.log(A); // 1

    • var은 함수 내에서만 지역 변수로 유지되기 때문에, 아래 코드에서는 전역 변수로 취급됩니다.
      if (true) {
      	var A = '1';
      }
      console.log(A); // 1
  • 블록 스코프 let, const
    • 블록 스코프는 블록 {} 내부에서 선언된 변수는 해당 블록에서만 접근 가능하다는 걸 의미합니다.
    • 아래 예시는 함수 스코프와 블록 스코프의 차이점을 보여줍니다.
      function test() {
      	for (var i=0; i<10; i++) {
          	...
      	}
      	console.log(i) // 접근 가능
      }
      test(); // 10
    • var의 경우 함수 스코프를 따르므로, 함수 내부에서는 변수 접근이 가능합니다.

      function test() {
      	for (let i=0; i<10; i++) {
          	...
      	}
      	console.log(i) // 블록 바깥에서 접근 불가능
      }
      test(); // Uncaught ReferenceError: i is not defined
    • 하지만 let, const는 블록 스코프를 따르므로 블록 바깥에서는 변수 접근이 불가능해서 오류가 나옵니다.

📌 변수의 선언과 할당

위에서 설명한 것처럼 varlet, const는 함수 스코프와 블록 스코프라는 큰 차이점이 있습니다. 하지만 그 외에도 차이점은 또 있습니다! 바로 선언과 할당의 방법입니다.

var : 재선언 가능 / 재할당 가능

var A = '1';
console.log(A); // 1

var A = '2'; // 변수의 재선언 가능
console.log(A); // 2

A = '3'; // 변수의 재할당 가능
console.log(A); // 3

우선 var는 변수의 재선언과 재할당이 가능합니다. 예시와 같이 마지막에 할당된 값이 변수에 저장되는 것을 볼 수 있습니다.

let : 재선언 불가능 / 재할당 가능

let A = '1';
console.log(A); // 1

let A = '2'; // 변수의 재선언 불가능
console.log(A); // Uncaught SyntaxError: Identifier 'A' has already been declared

A = '3'; // 변수의 재할당 가능
console.log(A); // 3

letvar 와 다르게 변수를 재선언할 시 해당 변수가 이미 선언되었다는 에러 메시지가 출력됩니다. 하지만 변수 선언 및 초기화 이후 반복해서 다른 값을 재할당할 수는 있습니다

const : 재선언 불가능 / 재할당 불가능

const A = '1';
console.log(A); // 1

const A = '2'; // 변수의 재선언 불가능
console.log(A); // Uncaught SyntaxError: Identifier 'A' has already been declared

A = '3'; // 변수의 재할당 불가능
console.log(A); // Uncaught SyntaxError: Identifier 'A' has already been declared

function func() {
	const list = ["A", "B", "C"]

    list = "D";
    console.log(list);
    // TypeError: Assignment to constant variable

    list.push("D");
    console.log(list); // ["A", "B", "C", "D"]
}

const 는 constant(상수)를 뜻하기 때문에 한 번만 선언이 가능하며 값을 재할당하는 것도 불가능합니다.
하지만 위 예제와 같이 배열과 오브젝트의 값을 변경하는 것은 가능합니다.

var, let, const 각각의 특징을 알아봤습니다. 그러면 왜 var의 사용을 지양하고 letconst를 사용해야 할까요?


📌 var 그리고 호이스팅

var는 위에서 확인했듯이 중복 선언과 재할당이 굉장히 자유로운 선언 방식입니다. 이런 특성은 간단한 코드나 짧은 코드에서는 큰 문제가 없겠지만 코드가 길어지면 길어질수록 오류가 나올 확률이 높아집니다.

이미 선언했던 변수명을 모르고 또 사용할 경우, 기존에 있던 변수는 전혀 다른 값을 가지게 됩니다. 그 경우, 그 변수를 사용하는 다양한 로직들에 치명적인 문제가 생깁니다.

그러면 왜 유독 var에서 이런 현상이 나타나는 것일까요?
그 이유는 바로 Hosting(호이스팅) 때문입니다.

그렇다면 호이스팅이란 무엇일까요?
간단하게 말하자면 선언과 할당이 분리된 것을 뜻합니다.

console.log(num); // undefined
var num; // 선언
num = 6; // 초기화

간단한 코드를 예시로 보여주면 위에 코드는 호이스팅을 거쳐서
실제로는 아래 코드처럼 작동하게 됩니다.

var num; // 호이스팅으로 인해 선언은 최상단으로 이동
console.log(num); // 호이스팅한 var 선언으로 인해 undefined 출력
num = 6; // 초기화는 호이스팅이 적용되지 않아서 최상단으로 이동하지 않습니다.

이렇듯 var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화합니다. 반면 letconst로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.
또한 호이스팅은 변수 말고도 함수도 똑같이 호이스팅 된답니다!

호이스팅이란 런타임시에 선언을 코드의 최상단으로 끌어올려 주는 것.
문제는 코드를 작성할 때 예상치 못한 실행 결과가 노출될 수 있다는 점입니다.
이를 방지하기 위해서 var를 지양하고 letconst를 습관화합니다.

📌 해결방법은?

일단 var를 지양하고 letconst를 쓰는 방법이 제일 쉬운 방법이겠죠?!
그리고 또 다른 방법은 const를 사용한 함수 표현식을 사용하는 것입니다.

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

const sum = function() {
  return 1 + 2
};

위 코드는 const를 사용한 함수 표현식을 간단하게 작성한 코드입니다.
const를 사용한 덕분에 이렇게 에러를 쉽게 찾을 수 있습니다.
이렇듯 익명 함수를 하나 만들어서 변수에 할당하는 것을 함수 표현식이라고 합니다!

profile
안녕하세요! 배우는 것을 좋아하는 개발자 JINJIN입니다.

0개의 댓글