본문 바로가기

Programming Language/Javascript

[Javascript] 배열 선언, 초기화의 모든 것 (Hacks for Creating Javascript Arrays)

이 글은 자바스크립트로 배열을 선언하는 방법들에 대해 설명한다.

배열 리터럴([])

일반적으로 배열 리터럴을 이용해 배열을 생성한다. 그러나 동적으로 배열을 생성하기에 최적의 방법은 아니다.

const array1 = [1, 2, 3];

배열 생성자(Array())

배열 생성자(Array())를 이용한 선언이 배열 리터럴의 대안이 된다. 아래 코드는 배열 생성자의 쓰임새를 보여준다.

// 매개변수(parameter)가 하나 이상일 때
// 인자(argument)를 요소로 가지는 새 배열을 생성한다.
// 배열의 길이는 인자의 개수로 설정된다.

const array1 = new Array(1, 2, 3);

console.log(array1); // [1, 2, 3]
console.log(array1.length); // 3


// 매개변수가 하나이고, 인자가 숫자일 때
// 인자만큼의 빈 슬롯을 가진 배열을 생성한다.
// 인자는 양의 정수여야 한다. 아니라면 에러가 난다.

const array2 = new Array(3);

console.log(array2); // Array(3) {length: 3}
console.log(array2.length); // 3


// 매개변수가 하나이고, 인자가 숫자가 아닐 때
// 인자를 요소로 가지는 새 배열을 생성한다.
// 배열의 길이는 1로 설정된다.

const array3 = new Array("3");

console.log(array3); // ["3"]
console.log(array3.length); // 1

위 예시를 통해 배열 생성자가 매개변수의 값과 개수에 따라 배열을 다른 방식으로 생성하는 것을 알 수 있다. 배열 생성자가 매개변수에 따라 배열을 생성하는 방법이 달라 모호하기 때문에 배열 생성자보다 배열 리터럴을 이용한 선언 방식이 권장된다. [출처]

of 배열 메서드(Array.of())

Array.of() 메서드는 배열 생성자와 유사하다. Array.of() Array()의 유일한 차이점은 그들이 한 개의 숫자 인자를 어떻게 처리하는지에 있다. Array.of(3)은 3을 요소로 가지는 길이 1의 배열을 생성한다. 이에 반해 Array(3)은 길이 3만큼 빈 슬롯을 담은 배열을 생성한다.

const array1 = Array.of(3); // [3]
const array1 = Array(3); // Array(3) {length: 3}

정해진 길이의 배열을 생성할 때

배열 생성자로 정해진 길이의 배열을 생성하는 경우에 대해 더 깊이 들여다보자. 생성자는 배열의 길이를 설정할 뿐 요소에 값을 설정하지 않는다(빈 슬롯).

const array1 = new Array(3);

console.log(array1.length); // 3

console.log(array1[0]); // undefined
console.log(array1[1]); // undefined
console.log(array1[2]); // undefined

위 코드를 보면 자칫 배열의 각 요소에 리터럴 undefined가 저장된 것처럼 생각할 수 있다. 그러나 실제로는 요소들이 존재하지 않는다.

다음 코드는 이를 더 잘 이해할 수 있게 해준다.

const array1 = Array(3);
const array2 = Array(1, 2, 3);

// array1에 대해 길이 속성만 존재한다.
console.log(Object.getOwnPropertyNames(array1)); // ["length"]

// array2에 대해 길이, 인덱스 속성이 존재한다.
console.log(Object.getOwnPropertyNames(array2)); // ["0", "1", "2", "length"]

이것은 배열의 요소를 순회하며 동작하는 배열 메서드들(map(), filter(), reduce())을 이용하지 못하게 한다. 만약 배열의 각 요소에 5를 채워넣고 싶다면 다음과 같은 시도를 할 것이다.

// 각 인덱스의 값을 5로 지정하려고 시도한다.
const array1 = Array(3).map(()=>5));

// 그러나 아무 일도 없었다.
console.log(array1[0]); // undefined
console.log(array1[1]); // undefined
console.log(array1[2]); // undefined

console.log(Object.getOwnPropertyNames(array1)); // ["length"]

여기에서 배열에 인덱스 속성이 존재하지 않기 때문에 map()이 동작하지 않는 것을 알 수 있다.

이 문제를 해결할 수 있는 세 가지 방법을 살펴보자.

1. fill 배열 메서드(Array.prototype.fill())

fill() 메서드는 배열의 모든 인덱스를 정적인 값으로 채운다. 다음은 간단한 예시이다.

// fill() 메서드를 이용해 배열의 각 인덱스를 5로 채운다.
const array1 = Array(3).fill(5);

// 의도한 대로 된다.
console.log(array1[0]); // 5
console.log(array1[1]); // 5
console.log(array1[2]); // 5

console.log(Object.getOwnPropertyNames(array1));
// ["0", "1", "2", "length"];

배열의 모든 요소가 5로 설정됨을 확인할 수 있다. 어떠한 정적인 값을 배열의 모든 인덱스의 요소로 설정하고 싶다면 fill() 메서드를 이용하면 된다.

2. from 배열 메서드(Array.prototype.from())

ES6 from() 메서드는 반복할 수 있거나 배열과 유사한 객체로부터 새로운 얕은 복사본을 생성한다. 다음은 간단한 예시이다. 

// fill() 메서드를 이용해 배열의 각 인덱스를 5로 채운다.
const array1 = Array.from(Array(3));

// 의도한 대로 된다.
console.log(array1[0]); // undefined
console.log(array1[1]); // undefined
console.log(array1[2]); // undefined

console.log(Object.getOwnPropertyNames(array1));
// ["0", "1", "2", "length"];

전에 나왔던 예시와 달리 위 예시에서는 리터럴 undefined가 배열 요소들의 값으로 설정되었고, 배열이 인덱스 속성을 가지는 것을 확인할 수 있다. 이제는 map(), filter()와 같은 배열 메서드를 사용할 수 있다.

Array.from() 메서드에 대해 한 가지 더 살펴볼 만한 점은, map function을 두 번째 인자로 가질 수 있다는 점이다. 이 함수는 배열의 모든 요소들에 대해 호출된다. 이것은 Array.from()의 결과로 map()을 호출하게 만든다. 다음은 간단한 예시이다.

//Array.from 메서드의 두 번째 인자로 map function을 넘겨주었다.
const array1 = Array.from(Array(3), (x, index) => index+1);

console.log(array1[0]); // 1
console.log(array1[1]); // 2
console.log(array1[2]); // 3

3. 스프레드 연산자 spread operator(...)

ES6 spread operator(...)는 배열의 요소들을 전개하기 위해 사용된다. 이때 배열의 요소가 없다면(빈 슬롯) 그 요소의 값을 리터럴 undefined로 설정한다. 이것은 Array.from()의 인자로 Array(n)을 넣어준 결과와 같다. 다음은 스프레드 연산자의 간단한 예시이다.

// fill() 메서드를 이용해 배열의 각 인덱스를 5로 채운다.
const array1 = [...Array(5)];

// 의도한 대로 된다.
console.log(array1[0]); // 5
console.log(array1[1]); // 5
console.log(array1[2]); // 5

console.log(Object.getOwnPropertyNames(array1));
// ["0", "1", "2", "length"];

배열이 인덱스 속성을 가지기 때문에 map(), filter() 메서드를 이용할 수 있다.

 

 

이 글은 다음 글의 일부를 번역, 요약했습니다. www.freecodecamp.org/news/https-medium-com-gladchinda-hacks-for-creating-javascript-arrays-a1b80cb372b/