자바스크립트 변수 선언에 관련된 팁들

퍼렁꽁치·2022년 5월 6일
1
post-thumbnail

이번 글에서는 자바스크립트 관련해서 변수 선언과 관련된 팁들을 글로 적어 공유하고자 한다.

1. const 로 변하지 않는 값을 표현하라

ES6 에서 등장한 const 로 변수를 선언하는 방법은, 기존의 var 키워드와 달리 재할당을 금지한다.
때문에 일반적으로 코드를 작성할 때는 const 를 우선으로 쓰는 것이 좋다.
그 이유는 가장 할 수 있는 것이 적기 때문에, 가장 안전하기 때문이다.

var taxRate = 0.1
var total = 100 + (100 * taxRate)
// 약 100줄의 코드
return `구매 금액은 ${total}입니다.`

위의 코드의 문제점이 무엇일까.
var 로 선언한 변수의 경우 재할당과 중복 선언 모두가 가능하기 때문에, 저기 숨은 100줄의 코드에서 어떤식으로 변경이 되었는지 일일히 확인해봐야 한다는 점이다.

const taxRate = 0.1
const total = 100 + (100 * taxRate)
// 약 100줄의 코드
return `구매 금액은 ${total}입니다.`

반면 이 코드는 저 100줄의 코드를 보지 않아도 taxRate 와 total 이란 변수가 재할당이 안 될 것이기 때문에 값을 정확히 예측할 수 있다.

가급적이면 const 키워드로 변수를 선언하는 이유는, 예측 가능하며 예측 불가능한 변수값 변경으로부터 안전하기 때문이다!

const 는 불변성을 의미하지 않는다.

이게 무슨 뜻일까?
말 그대로 const 에 할당한 값이 불변값을 의미하지는 않는다는 뜻이다.
변수를 재할당하는 것은 불가능하지만, 값을 바꾸는 것은 가능하다.

const discountable = []

for (let i = 0; i < cart.length; i++) {
	if (cart[i].discountAvailable) {
    	discountable.push(cart[i])
    }
}

위의 코드에서 discountable 변수에 할당된 배열에는 아이템이 추가될 수 있다. 즉 const 로 선언한 변수라도 값이 변할 수는 있다.
하지만 이 경우 const 를 사용하는 의미가 있을까?
때문에 const 로 선언한 변수의 경우는 될 수 있으면 조작(mutation)을 피하는 것이 좋다!

const discountable = cart.filter(item => item.discountAvailable)

discountable 배열의 아이템 자체는 변경될 수 있다.
그러나 코드상에서 더 이상의 조작이 가해지지 않기 때문에 해당 변수의 특성을 유지할 수 있다.

2. let 과 const 로 유효범위 충돌을 줄여라

값이 변경되는 경우에는 let 이 아주 좋은 선택지가 될 것이다.
var 는 lexical scope 를 따르지만, letconst 는 block scope 를 따르면서 둘 간의 차이가 발생한다.

먼저 코드의 요구사항을 확인해보면,
- 재고가 없으면 0 을 반환한다.
- 어떤 상품이 할인 중이고 재고가 있다면 할인 가격을 반환한다.
- 어떤 상품이 할인 중이 아니거나 할인 중이라도 할인 상품의 재고가 없다면 정상 가격을 반환한다.

function getLowestPrice(item) {
	var count = item.inventory
    var price = item.price
    if (item.salePrice) {
    	var count = item.saleInventory
        if (count > 0) {
        	price = item.salePrice
        }
    }
  	if (count) {
    	return price
    }
  
  	return 0
}

위 코드는 헷갈릴 수 있지만 치명적인 문제점을 안고 있다.
var 키워드는 렉시컬 스코프, 즉 함수레벨 스코프를 가진다. 블록레벨 스코프가 아니다.
때문에 하나의 함수 안에서 count 변수가 재할당이 일어나면서 버그를 일으키게 되고, 의도한 동작이 이루어지지 않게 될 수 있다.
때문에 이런 경우를 방지하기 위해서라도 let 키워드로 변할 수 있는 값의 변수를 선언해주는 것이 좋다.

3. 블록 유효 범위 변수를 정보를 격리하라

먼저 자바스크립트로 DOM 을 조작하는 경우를 보자

<ul>
  <li> 클릭하면 0 </li>
  <li> 클릭하면 1 </li>
  <li> 클릭하면 2 </li>
</ul>
const items = document.querySelectorAll('li')
for (var i = 0; i < items.length; i++) {
	items[i].addEventListener('click', () => alert(i))
}

이 코드는 결과적으로 어떤 li 요소를 클릭해도 3을 출력한다.

밑에 코드를 봐보자

function addClick(items) {
	for (var i = 0; i < items.length; i++) {
    	items[i].onClick = function () { return i }
    }
  	return items
}
const example = [{}, {}, {}]
const clickSet = addClick(example)
clickSet[0].onClick() // 2
clickSet[1].onClick() // 2
clickSet[2].onClick() // 2

DOM 을 직접 조작하는 경우가 아니더라도 위의 코드는 항상 숫자 2를 리턴한다. 왜일까?
이는 바로 유효 범위의 문제다.
var 로 할당한 변수는 함수 유효 범위를 따른다. 즉, 함수 내에서 마지막으로 할당한 값을 참조한다.

함수 밖에서 var 로 변수를 선언했을 때 함수는 항상 가장 마지막에 재할당된 변수를 참조하기 때문에 위의 두가지 경우의 코드 모두 가장 마지막 i 값을 가지는 것이다.

전통적인 해결 방법

이 방법을 해결하기 위한 전통적인 방법은 클로저, 고차함수, 즉시실행함수를 이용하는 것이었다.

function addClick(items) {
	for (var i = 0; i < items.length; i++) {
    	items[i].onClick = (function (i) {
        	return function () { return i }
        }(i))
    }
  return items
}
const example = [{}, {}, {}]
const clickSet = addClick(example)
clickSet[0].onClick() // 0
clickSet[1].onClick() // 1
clickSet[2].onClick() // 2

클로저는 외부함수의 내부 값을 기억하고 은닉한다.
고차함수는 즉시 실행 함수로써 그 자리에서 실행되어 클로저를 리턴하고 있다.
클로저는 var 로 선언한 변수 i 가 가지고 있는 값을 기억하고 그것을 그대로 리턴한다.
때문에 의도한대로 동작을 수행할 수 있다.

그러나 문제는 이 방법이 다소 복잡하다는 것이다.
이것을 let 은 쉽게 해결할 수 있다.

let 을 통한 해결방법

function addClick(items) {
	for (let i = 0; i < items.length; i++) {
    	items[i].onClick = function () { return i }
    }
  	return items
}
const example = [{}, {}, {}]
const clickSet = addClick(example)
clickSet[0].onClick() // 0
clickSet[1].onClick() // 1
clickSet[2].onClick() // 2

let 을 통해서 대단한 변경을 하지 않았다. 단지 var 키워드를 let 키워드로 변경한 것이 다지만, 원하는 동작을 수행할 수 있게 됐다.
이게 가능한 이유는, let 이 블록 레벨 스코프를 따르기 때문이다.

블록 내에서 선언한 변수는 해당 블록에서만 유효하다.
때문에 반복되어 값이 변경되어도, 이전에 선언한 함수의 값은 변경되지 않는다.

따라서 var 로 할 수 있는 거의 모든 것이 let 으로 대체가 가능하므로 가급적이면 let 을 사용하는 것이 좋다.


참고자료

  • <자바스크립트 코딩의 기술> (조 모건 지음)
profile
무엇이든 될 수 있는 멋쟁이 토마토🍅 프론트 꿈나무💙

0개의 댓글