문제에 대비하기

김정훈·2023년 4월 3일

JavaScript

목록 보기
7/10

var, let, const

자바스크립트가 처음 만들어 졌을 때에는 let, const가 존재하지 않았고, 모두 var를 사용했다. 하지만 var는 각종 문제점들을 갖고 있으므로 더 이상 사용하지 않을 것을 권장한다.

var는 왜 사용하지 않는지 어떤 문제가 있는지 알아보자.

  1. 선언 없이도 사용 가능하다.
notDeclared = 1; // 미리 선언한 부분이 없을 시 var로 만들어짐
console.log(notDeclared); // 1

notDeclared라는 변수는 어떠한 선언자도 표현되어 있지 않지만 정상적으로 값이 출력되는 것을 볼 수 있다.

선언문이 없이 변수의 이름만 작성해도 자동으로 var의 선언문으로 만들어지기 때문이다.

자바스크립트에서 의도한 문법을 벗어나는 경우가 발생한다.

  1. 재선언 가능
    let, const는 동일 스코프 내에서 같은 이름의 변수를 선언할 수 없다.
let a = 1;
let a = 2; // ⚠️ 오류

const b = 1;
const b = 2; // ⚠️ 오류

반면 var는 가능하다.

var c = 1;
var c = 2;

재선언이 가능하면 스코프내에서 이미 선언해서 사용한 변수를 그것을 인지 못하고 있다가 재선언 한다면 실수의 여지가 될 수 있다.

  1. 블록 레벨 스코프 무시
    letconst는 선언된 스코프 블록{} 내에서만 유효하다.
let num1 = 1;
{
  let num1 = 2;
  {
    let num1 = 3;
  }
}

console.log(num1); // 1

반면 var는 블록 스코프를 무시한다. 블록 내부에서 선언한 값을 블록 외부에서도 사용 할 수 있게 된다.

스코프를 활용해서 변수나 상수의 범위를 특정 할 수 없게되니 블록 바깥에 선언된 변수들을 모두 신경써야 하는 번거로움이 발생한다.

무서운 점은 for문의 스코프도 무시해버린다는 것이다.

var num2 = 1;
{
  var num2 = 2;
  {
    var num2 = 3;
  }
}

console.log(num2); // 3

// for문의 스코프도 무시
for (var i = 0; i < 5; i++) {
  var pow2 = i ** 2;
  console.log(pow2);
}
/*
0
1
4
9
16
*/
console.log(i, pow2); // 5 16

(다행히도 함수의 스코프는 유효하다. 그래도 사용하지 말자)

  1. 호이스팅
    본래 선언하지 않은 변수를 사용하려고 하면 오류가 발생한다.

다음 코드를 보자

console.log(hoisted1); // 💡 오류발생 X, 대신 undefined 반환

var hoisted1 = 'Hello';

console.log(hoisted1)

이 코드는 선언하기 이전의 변수를 사용하려고 했지만 오류가 발생하지 않았다. 자바스크립트에서는 함수 뿐만 아니라 변수나 상수도 호이스팅이 되는데, 값이 할당되지 않은 상태로 호이스팅된다.

따라서 위 코드는 오류가 발생하지 않고, undefined가 출력된다.

반면 let, const는 오류가 발생한다.

console.log(hoisted2); // ⚠️ 오류

let hoisted2 = 'Hello';

console.log(hoisted2)

그렇다면 let, const는 호이스팅이 되지 않는 걸까?

결론부터 말하면 호이스팅된다. 호이스팅 되지만 undefined로 초기화 되지 않고 시간상 사각지대(TDZ)라는 영역에 속하게 된다.

시간상 사각지대는 코드의 작성 순서가 아니라 코드의 실행 순서에 의해 형성되기 때문에 붙여진 이름이다. (자바스크립트는 위에서 부터 한 줄씩 실행)

엄격 모드

기존의 느슨한 모드에서 허용되던, 문제를 유발할 수 있는 코드들에 오류를 발생시킨다.

  1. 선언되지 않은 변수 사용시 오류 발생
    엄격 모드가 아닌 상태에서는 변수를 선언하지 않고도 사용할 수 있었다.
notDeclared = 1; // 💡 암묵적으로 전역 var 변수로 선언

하지만 자바스크립트 문서 최상단use strict라는 키워드를 작성하면 엄격모드가 된다.

// ⚠️ 새로고침 후 실행해볼 것
// 선언되지 않은 변수 사용 금지
'use strict'; // 쌍따옴표도 가능

notDeclared = 1; // 오류 발생!
  1. 변수, 함수, 인자등 삭제불가한 것을 삭제시 오류 발생
// 실제로 지워지지도 않지만 오류를 발생시키지도 않음

let toDelete1 = 1;
delete toDelete1;

console.log('1.', toDelete1);
'use strict';

let toDelete2 = 1;
delete toDelete2;

function funcToDel2 () { console.log(true); }
delete funcToDel2;

⛔ Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.

  1. 인자명 중복시 오류 발생
'use strict';

function add(x, x) {
  return x + x;
}

console.log(add(1, 2));

⛔ Uncaught SyntaxError: Duplicate parameter name not allowed in this context

이런 엄격모드는 클래스나 모듈과 같은 ES6문법 사용시 기본으로 적용된다.
하지만 논리적인 오류와 같은 개발자의 책임이 있는 부분은 엄격 모드라고 해도 잡아주지 않는다.

옵셔널 체이닝

유효하지 않을 수 있는 참조에 의한 문제들을 방지하기 위한 기능이다.

네트워크 요청과 같은 어떤 값이 들어올지 모르는, 즉 제어 할 수 없는 데이터를 접근하려 할 때 발생하는 오류를 대비하는 방법이다.

API요청을 하고 정확히 모든 데이터가 넘어 올것이라 가정하고 개발한다면 심심치 않게 오류를 마주 할 수 있을 것이다.

그럼 응답을 받을 때 마다 필요한 데이터가 있는지 일일이 확인해야 할까?

// 방법 1
const result = notSure();

if (result) {
  if (result.data1) {
    if (result.data1.data2) {
      console.log(result.data1.data2.data3);
    }
  }
}

... 너무 장황하다. 데이터의 구조가 복잡해질수록 개발자의 머리도 같이 복잡해지고 오류 발생 가능성도 높아질 것이다.

?.-옵셔널 체이닝

호출 대상이 undefinednull이어도 오류를 발생시키지 않는다.

오류 대신 undefined를 반환한다. 있을지 없을지 확신할 수 없는 것으로 부터 값을 읽거나 실행할 때 사용한다.

let undef = undefined;

console.log(
  undef?.x,
  undef?.['x'],
  undef?.[1],
  {}.func?.()
);
// undefined undefined undefined undefined

실전에서 예측 불가능한 값들에 대해서 안전하고 간편하게 코드를 작성 할 수 있을 것 같다.

0개의 댓글