JS - let과 const

20660 단어 TILJavaScriptES6ES6

이전 Javascript 포스팅인 Block Scope에 이어서 ES6의 let과 const에 대해서 정리합니다.

let

재할당 가능

let은 재할당이 가능하다.

let a = 1
a = 2
console.log(a)

반복문 내에서의 함수 실행시

var의 경우, for문 내에서 함수를 실행하면 첫 번째 예시와 같이 의도와 달리 오작동한다. 때문에 두 번째 예시처럼 즉시실행함수(IIFE)로 감싸서 각각의 i를 직접 넘겨줘야 정상 출력되었다. 하지만 let의 경우에는 Block Scope를 가지기 때문에 그럴 필요가 없다.

/* var의 문제 */
var funcs = []
for (var i = 0; i < 10; i++) {
  funcs.push(function () {
    console.log(i)
  });
}
funcs.forEach(function (f) {	// 의도와 달리 10이 10번 출력
  f()
})
/* var의 문제를 IIFE로 해결 */
var funcs = []
for (var i = 0; i < 10; i++) {
  (funcs.push(function () {
    console.log(i)
  }))(i);
}
funcs.forEach(function (f) {	// 0 ~ 9 순차대로 정상 출력
  f()
})
/* let의 block scope로 인한 근본적인 해결 */
let funcs = []
for (let i = 0; i < 10; i++) {
  funcs.push(function () {
    console.log(i)
  })
}
funcs.forEach(function (f) {	// 0 ~ 9 순차대로 정상 출력
  f()
})

const

재할당 불가

constconstant variable의 약자이며 상수 변수라는 의미를 가진 말그대로 상수이기 때문에 재할당이 불가능하다.

const PI = 3.141593
PI = 3.14  //	Error

선언시에 할당

const는 선언과 동시에 할당해줘야한다. 그렇지 않으면 에러가 발생한다.

const PI;  //	Error

참조 타입 데이터

상수 변수인 const에 참조 타입의 데이터를 할당하면 const내부 property는 상수가 아니다. 다시말해 내부 property는 변경이 가능하다. 이해를 위해 아래의 그림과 예시를 보자.

const OBJ = {
  a: 10,
  b: 20
};
obj1 = 30;  // Error - 변경 불가
OBJ.a = 30;
console.log(OBJ); // {a: 30, b: 20} - property a값 변경 가능

OBJ가 할당된 주소값은 상수이고 내부 property는 상수가 아니다. 때문에 예시에서 OBJ.a의 값을 변경할 수 있다.

내부 property도 상수로 만들기 위해서는?

상수에 할당된 참조 타입 데이터 내부 property도 상수로 만들기 위해서는 Object.freeze()Object.defineProperty()라는 Object의 메소드를 사용하는 방법이 있다.

const OBJ1 = {};

Object.defineProperty(OBJ1, 'a', {
  value: 10,
  writable: false,
  configurable: false
});
OBJ1.a = 200; // Error - 변경 불가

const OBJ2 = {
  a: 30,
  b: 40
};

Object.freeze(OBJ2)
OBJ2.a = 100; // Error - 변경 불가

참조 타입 데이터를 중첩하고 있으면?

const OBJ3 = {
  a: 10,
  b: 20,
  c: [1, 2, 3, 4, 5],	// 참조 타입 데이터인 배열
};

Object.freeze(OBJ3)
OBJ3.a = 100;	      // Error

OBJ3.c.push(6);
console.log(OBJ3.c);  // 6이 추가됨(변경 가능)

상수에 참조 타입 데이터의 내부 property가 또 참조 타입 데이터이면 Object.freeze() 메소드를 사용하더라도 변경 가능하다. Object.freeze() 메소드는 참조 타입 데이터를 반영하지 못하기 때문이다.

이처럼 중첩된(Nested) 참조 타입 데이터의 경우에는 다음과 같이 해결 해야한다.

  1. OBJ3Object.freeze() 메소드로 얼린다.
  2. OBJ3내부 property를 순회하면서 해당 property가 참조 타입이면 1번을 반복한다.

이 과정을 재귀를 통해서 구현하면 모든 내부 property도 변경할 수 없는 완전한 상수를 만들 수 있다. 이를 DeepFreeze라고도 한다. 이 방법은 추후에 정리할 깊은 복사(Deep Copy)에서도 동일하다.

반복문 내부의 상수

for문 내부에서 const를 사용했을 때 for in 문 같은 경우에 생각해보면 상수에 재할당 되기 때문에 Error가 날 것 같지만 이상하게 정상동작한다. 하지만 for문의 경우에는 재할당이 되지 않아서 0을 한번 출력하고는 Error가 발생한다. 뭔가 일괄적이지 않은 느낌이지만 알고는 있자.

let obj = {
  a: 10,
  b: 20,
  c: 30,
};

for (const a in obj) {
  console.log(a);	// a, b, c 출력 - 정상 동작
}

for (const i = 0; i < 10; i++) {
  console.log(i);	// 0 출력 후 Error
}

TIP. 주로 객체를 다루는 FE환경에서는 const를 잘 사용하지 않을 뿐만 아니라 클린 코드를 위해서 let보다는 최대한 const를 사용도록 노력하자.

전역 객체의 property

전역 공간에서 var가 선언되면 전역 변수와 전역 객체의 property가 동시에 할당되었다. 하지만 letconst는 더이상 전역 객체의 property가 되지 않고 오직 전역 변수로 할당된다.

var a = 10;
console.log(a)		// 10
console.log(window.a)	// 10
delete a;		// false
delete window.a;	// false
console.log(a)		// 10
console.log(window.a)	// 10

let b = 20;
console.log(b)		// 20
console.log(window.b)	// undefined ----- 전역 객체의 property가 아님
delete b;		// false --------- 전역 객체의 property가 아니기 떄문에 삭제 불가
delete window.b;	// true ---------- undefined라서 true
console.log(b)		// 20
console.log(window.b)	// undefined

위의 예시를 보면 let의 경우에 전역 객체의 property(window.b)가 아닌 전역 변수(b)에만 할당되고 있음을 확인할 수 있고 const도 마찬가지로 동일하게 동작한다.

참조


좋은 웹페이지 즐겨찾기