[Javascript] 배열 초기화 시 new Array()보다는 []를 사용하자

2019. 11. 28. 12:33Programming/JavaScript

반응형

[Javascript] 배열 초기화 시 new Array()보다는 []를 사용하자

The Javascript Handbook을 읽던 도중 new Array()를 사용하여 배열을 초기화하는 것은 권장하지 않는다는 내용을 발견했는데, 그 이유에 대해서는 따로 기술하지 않고 있었다. 다른 분들께 질문을 해보니 직관성 및 일관성과 관련된 내용과, ECMA문서의 22.1.1.2 Array(len)항목의 내용을 볼 수 있었다. 아래는 해당 내용을 정리한 내용이다. (사실 서문에 모든 내용이 다 들어가있다' ㅅ';)

The Javascript Handbook의 Arrays챕터에 기재되어있는 Initialize array항목을 보면, typed array를 초기화하는 게 아닐때는 new Array()로 배열을 초기화하지 말라는 내용이 있다. 하지만 그 이유에 대해서는 따로 기재된 내용이 없다.

const a = new Array() //never use
const a = new Array(1, 2, 3) //never use

[]대신 new Array()를 사용해도 초기화는 될텐데, 왜 사용하지 말라고 하는걸까? 심지어 주석에는 //never use라고 적혀있을 정도다. 궁금해서 다른 분들에게 물어보고, 답변과 함께 ECMAScript 문서의 내용을 정리해봤다.

ECAMScript 문서 22.1.1.1 Array() 항목을 확인해보자. new Array()에 전달하는 인자값이 아무것도 없는 경우, 다음과 같이 길이가 0인 Array 객체를 반환하게 된다.

22.1.1.1 Array ( )

This description applies if and only if the Array constructor is called with no arguments.

  1. Let numberOfArgs be the number of arguments passed to this function call.
  2. Assert: numberOfArgs = 0.
  3. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
  4. Let proto be ? GetPrototypeFromConstructor(newTarget, "%Array.prototype%").
    • Return ! ArrayCreate(0, proto).

일단 여기서 new Array()를 호출했을 때 결과 자체는 []을 사용했을때와 동일하다는 것을 알 수 있다. 다만 코드의 길이는 new Array()를 호출했을 때보다 []를 사용하는 게 더 짧아지게 된다. 글자수뿐만 아니라 빈 배열을 생성한다는 점에서, []를 사용하는 쪽이 좀 더 직관적이기도 하다. 하지만 여기까지만 봐서는 new Array()를 사용하지 말라는 내용이 잘 이해되지 않는다. 이제 new Array()에 인자값을 1개 전달하는 경우, []를 호출하는 것과 어떤 차이점을 보이는지 살펴보도록 하자.

22.1.1.2 Array ( len )

This description applies if and only if the Array constructor is called with exactly one argument.

  1. Let numberOfArgs be the number of arguments passed to this function call.
  2. Assert: numberOfArgs = 1.
  3. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
  4. Let proto be ? GetPrototypeFromConstructor(newTarget, "%Array.prototype%").
  5. Let array be ! ArrayCreate(0, proto).
  6. If Type(len) is not Number, then
    a. Perform ! CreateDataPropertyOrThrow(array, "0", len).
    b. Let intLen be 1.
  7. Else,
    a. Let intLen be ToUint32(len).
    b. If intLen ≠ len, throw a RangeError exception.
  8. Perform ! Set(array, "length", intLen, true).*
  9. Return array.

인자를 1개 전달했을때는 new Array()를 이용하여 배열을 초기와했을때와, []를 이용하여 배열을 초기화했을때의 차이가 명백해진다. 값이 Number인지 아닌지에 따라서 달라지는데, Number가 아닐 경우에는 배열의 첫 번째 요소로 할당이 된다. 하지만 값이 Number일 경우에는 인자로 넘겨진 값과 같은 크기의 빈 배열이 생성된다.

const a = new Array("3") // ["3"]
const b = new Array(3) // [empty x 3]
const c = ["3"] // ["3"]
const d = [3] // [3]

위에서 보이듯이 new Array()를 사용하여 배열을 초기화 했을때는, []를 사용해서 배열을 초기화했을때와 다르게 동작한다. 일관성이 부족하다는 느낌도 없잖아있다.

7-b를 보면 len값을 ToUInt32를 사용하여 정수형으로 변환한다. 그리고 len값과 ToUInt32(len)의 결과값이 같지 않으면, RangeError exception을 발생시킨다는 걸 알 수 있다. 한번 소수를 넘겨보자.

const e = new Array(1.2) // Uncaught RangeError: Invalid array length
const f = [1.2] // [1.2]

new Array(1.2)를 호출하면 인자로 전달한 1.2를 정수로 변경하면, 당연히 1.2는 아니지 않겠는가. 결국 7-b에 의해서 RangeError exception을 뱉어버린다. 반면 []를 통해서 초기화한 경우에는, RangeError exception이 발생할 일이 없다.

22.1.1.3 Array(...items)의 내용은 22.1.1.1 Array()과 마찬가지로, []을 이용할때와 결과적인 차이를 보이지 않는다. 즉, new Array()를 사용하여 배열을 초기화하지 않는 이유는 22.1.1.2 Array(len)에서 len값이 Number로 주어지는지 아닌지, 그리고 len값이 정수인지 아닌지에 따라서 동작이 다르기 때문인 듯 하다. 직관성, 그리고 일관성의 문제라고 해야하나.

앞으로는 배열을 초기화할 때, new Array()대신 []를 사용해야겠다. ' ㅅ')

반응형