아래 내용은 학원 수업과 "모던 자바스크립트 Deep Dive : 이웅모 저"를 읽고 정리한 내용입니다.

배열

여러 개의 값을 순서대로 나열한 가장 기본적이며, 많이 사용하는 자료구조이다. 이 때 배열이 가지고 있는 값은 요소라고 하고, 요소의 갯수를 나타내는 프로퍼티를 length라고 한다. 요소는 숫자로 된 인덱스를 가지고 있으며, 배열의 요소를 참조하기 위해서는 대괄호 표기법을 사용해야 한다.

배열 요소의 참조

잠시 객체를 공부 했던 때로 돌아가서 생각해보면, 객체의 프로퍼티에 접근하기 위해서는 마침표 표기법 혹은 대괄호 표기법을 사용할 수 있다고 했었다. 이 때 객체의 프로퍼티 키는 식별자 네이밍 규칙을 준수하는 것이 좋은데, 이 경우에는 마침표 표기법과 대괄호 표기법을 모두 사용해서 참조할 수 있다고 했었다. 하지만 식별자 네이밍 규칙을 준수하지 않은 프로퍼티 키는 대괄호 표기법만 사용할 수 있고, 대괄호 안에 작성한 프로퍼티 키를 쌍따옴표로 감싸줘야 한다고 했었다. 이 때 약간의 예외가 있었는데, 숫자로만 된 식별자는 대괄호 표기법을 사용하되, 대괄호 안에 쌍따옴표를 생략할 수 있었다. 정리해보자면 배열의 인덱스는 숫자로 된 프로퍼티 키와 마찬가지인 것이다.

자바스크립트의 배열

사실 자바스크립트의 배열은 배열이 아닌 객체이지만, 일반적인 객체와 다른 아래의 특징을 가지고 있다.
1. 요소(값)가 순서를 가지고 있다.
2. length 프로퍼티를 가지고 있다. (요소의 개수를 나타냄)
이 두가지 특징으로 인하여 for문으로 대표되는 반복문을 사용하여 요소에 순서대로 접근할 수 있는 것이다.

밀집 배열과 희소 배열

위에서 자바스크립트의 배열은 배열이 아니라고 얘기했던 이유에 대해서 얘기를 해보자.
보통 일반적인 자료구조에서 말하는 배열은 동일한 크기의 메모리 공간이 (메모리 공간과 공간 사이에)빈틈없이(연속적으로) 나열된 자료구조를 말하고, 이러한 구조를 가진 배열을 밀집 배열이라고 한다.

하지만 자바스크립트의 배열은 이러한 자료구조와는 다른 특징을 가지고 있다. 자바스크립트의 요소는 모든 타입을 값으로 가질 수 있고, 각 요소의 타입 또한 통일되지 않아도 상관 없다. 때문에 각 요소는 동일한 크기의 메모리 공간을 가지고 있지 않을수도 있고, 연속적으로 나열되어 있지 않을 수도 있다. 이러한 자료구조를 가진 배열을 희소 배열이라고 한다. 다시 말하면 일반적인 배열을 흉내 낸 객체인것이다.

일반적인 배열과 자바스크립트 배열의 장.단점

이렇게 일반적인 배열과 자바스크립트의 배열은 다른 특징을 가지고 있고, 때문에 각각의 장점과 단점이 다르다.

일반적인 배열은 (각각의 값이 동일한 메모리 공간을 차지하고 있고, 메모리 공간 사이에 빈 공간이 없으므로)인덱스를 통해 요소에 빠르게 접근이 가능하다. 하지만 이런 자료 구조를 유지하기 위해서는 배열에 요소를 추가하거나 삭제할 경우 해당 요소 뿐만 아니라 더 많은 요소들을 움직여야 하므로 효율이 떨어지게 된다.
반면 자바스크립트의 배열은 인덱스로 요소에 접근하는 것은 일반적인 배열보다는 아무래도 느리다. 하지만 요소를 추가하거나 삭제하는 경우는 일반적인 배열보다 빠르다.

배열의 length

배열의 length 프로퍼티는 요소의 개수를 나타낸다고 했고, 이 값은 배열에 요소를 추가하거나 삭제할 경우 자동으로 갱신된다. 그런데 lengt는 명시적으로 값을 할당할 수 있다. 이 때 실제 length보다 작은 값을 할당할 경우에는 실제로 배열의 길이가 줄어들게 된다. 하지만, length보다 큰 값을 할당하는 경우에는 배열의 길이가 늘어나는 것은 아니다.

자바스크립트의 배열은 희소배열이라고 했는데, 희소 배열의 length는 배열 요소의 개수와 일치하지 않으며, 희소 배열의 length는 실제 요소의 개수보다 언제나 크다. (단, 희소 배열을 생성하는 것은 좋지 않다.)

배열의 생성

함수와 객체가 그랳던 것처럼 배열 역시 다양한 방법으로 생성할 수 있다. 이 때 가장 간단한 방법은 언제나 그랬든 리터럴로 직접 생성하는 방식이다.

배열 리터럴

배열은 대괄호[]안에 0개 이상의 요소를 쉼표로 구분해서 작성하는데, 요소를 작성하지 않으면 빈 배열이 된다.

let arr = [1, 2, 3];
let emptyArr = [];

Array 생성자 함수

array 생성자 함수는 인수의 개수에 따라 다르게 동작을 하고, new 연산자와 함께 호출하지 않아도 배열을 생성하는 생성자 함수로 동작한다. (함수 내부에서 new.target을 확인한다.)

인수가 전달되지 않았을 경우

빈 배열을 생성한다.

let emptyArray = new Array();
console.log(emptyArray); // []

인수가 1개만 전달되었을 경우

전달된 인수를 length의 프로퍼티 값으로 갖는 배열을 만들고, 배열의 요소는 존재하지 않는 희소 배열이 된다.

let arrElem1 = new Array(5);
console.log(arrElem1); // [ <5 empty items> ]
console.log(arrElem1.length); // 5

인수가 2개 이상, 또는 숫자가 아닌 인수가 1개 이상 전달된 경우

전달된 인수를 요소로 갖는 배열을 만든다.

let arrElem2 = new Array(5, 3);
console.log(arrElem2); // [5, 3]

let arrElemText = new Array("element");
console.log(arrElemText); // ['element']

array.of

전달된 인수를 요소로 갖는 배열을 생성한다.

let arrOf = Array.of(5);
console.log(arrOf); // [5]

array.from

유사 배열 객체 혹은 이터러블 객체를 인수로 전달받아 배열로 변환한다.

let arrFrom = Array.from('kyuree');
console.log(arrFrom) // ['k', 'y', 'u', 'r', 'e', 'e']

let arrFrom2 = Array.from({ length: 2, 0: "a", 1: "b" });
console.log(arrFrom2); // [ 'a', 'b' ]

배열 요소의 추가와 갱신

객체와 마찬가지로 배열도 존재하지 않는 인덱스에 값을 할당하면 동적으로 요소가 추가되고, 이미 존재하는 요소에 값을 재할당하면 요소의 값이 갱신된다. 또한 객체와 마찬가지로 요소를 동적으로 삭제하는 것도 가능하다. 이렇게 동적으로 요소를 추가하거나 삭제하는 경우 length 값은 자동으로 갱신된다.

length보다 큰 인덱스에 값을 추가했을 때 기존의 요소와 새로 추가된 요소 사이의 요소들에 값을 명시적으로 추가 하지 않은 경우 해당 요소들이 생성되는 것은 아니므로 유의해야 한다.

특이한 점은 배열에도 프로퍼티 추가가 가능하다는 점이다. 정수가 아닌 값을 인덱스처럼 사용하여 값을 할당하면 요소가 아닌 프로퍼티가 추가되게 되는데, 이 때 프로퍼틴는 length와는 무관하다. (요소의 개수만이 length와 연관이 있다.)

자바스크립트의 배열은 결국 객체라고 했다. 때문에 delete 연산자를 사용하여 특정 요소를 삭제할 수 있다. 하지만 delete 연산자를 사용하여 요소를 삭제하면 배열은 희소배열이 되고, length 값은 변화하지 않으므로 delete 연산자는 사용하지 않는 것이 좋다. 만약 배열의 요소를 삭제해야 한다면, array.prototype.splice 메서드를 사용해야 한다.

자바스크립트는 배열을 다룰 때 유용한 빌트인 메서드를 다양하게 제공한다. 이 때 메서드들은 배열의 원본을 직접 변경하는 메서드와 메서드를 통해 동작을 수행한 뒤 해당 배열을 새로 만들어서 반환하는 메서드들로 나뉘게 된다. 원본 배열을 직접 변경하게 되면, 외부 상태를 변경하게 되므로 새로운 배열을 만들어서 반환하는 메서드들을 사용하는 것이 좋다.

스프레드 문법

스프레드 문법은 ...을 사용하여 순회 가능한 값(배열, 문자 등)들의 집합을 개별적인 값들의 목록으로 만들어 준다. 하지만 스프레드 문법을 실행한 결과는 값이 아니므로 변수에 직접 할당할 수는 없다.
이 때 스프레드 문법은 Rest 파라미터를 표시하는 ...과 형태가 동일하다. 하지만 스프레드 문법은 Rest 파라미터와는 하는일이 반대이다. 따라서 ...을 어디에서 사용하는지에 따라 스프레드 문법이 되는지, 아니면 Rest 파라미터로 사용하는 것인지 달라지게 된다. (사용되는 문맥을 잘 파악하는 것이 중요하다)

const arr = [1, 2, 3];
console.log(...arr); // 1 2 3

디스트럭처링 할당

배열 혹은 객체를 분해해서 1개 이상의 변수에 각각 값을 할당하는 것을 말한다.

ES6 이전에 배열 또는 객체의 요소, 값을 변수에 할당하기 위해서는 배열의 인덱스 혹은 프로퍼티 키로 직접 접근하여 변수에 할당해야 했었다. 하지만 디스트럭처링 할당을 사용할 수 있게 된 ES6 이후에는 간단하게 할 수 있게 되었다.

// es5
const arr = [1, 2];

const first = arr[1];
const second = arr[2];

console.log(first); // 1
console.log(second); // 2

배열 디스트럭처링 할당

배열의 경우 배열을 뜻하는 대괄호 안에 각각의 값을 할당할 변수의 이름을 쉼표로 구분하여 작성한 뒤 할당 기호 뒤에 해당 배열을 할당하면 배열에 작성되어 있는 순서대로 변수에 할당되게 된다.

배열 디스트럭처링 할당을 사용할 때 기본값을 사용할 수도 있는데, 이 때 기본값이 작성되어 있다고 하더라도 값을 할당하게 되면 할당한 값이 우선된다. (나중에 작성한 값이 재할당 되는 것과 마찬가지라고 이해할 수 있을 것 같다.)

const arr = [1, 2];
const [first, second] = arr;

console.log(first); // 1
console.log(second); // 2

배열 디스트럭처링 할당에서는 Rest 파라미터와 유사하게 Rest 요소를 사용할 수 있는데, 사용법은 Rest 파라미터와 동일하다.

const arr = [1, 2, 3];
const [first, ...secondArr] = arr;

console.log(first); // 1
console.log(second); // [2, 3]

객체 디스트럭처링 할당

배열에서 디스트럭처링 할당을 하기 위해서는 작성 순서를 유의하여 작성하면 되었었다. 하지만, 객체는 작성 순서에는 의미가 없고, 프로퍼티 키를 기준으로 사용할 수 있다. 값을 할당 받을 변수의 이름과 디스트럭처링 문법을 사용할 객체의 프로퍼티 키의 이름이 동일하면 해당 값을 변수에 할당 받을 수 있게 된다.

하지만 객체의 프로퍼티 키와 변수 이름을 동일하게 사용하고 싶지 않을 경우에는 할당 받을 객체의 프로퍼티 키 이름을 먼저 작성하고 :기호를 사용한 뒤에 변수로 사용될 식별자 이름을 작성한 뒤에 객체를 할당해주면 된다.

const student = {name: 'kyuree', age: 38};

// es5

const name = student.name;
const age = student.age;

console.log(name, age); // kyuree 38

// es6

const {name, age} = student;

console.log(name, age); // kyuree 38

// es6 (프로퍼티키와 다른 변수 이름을 사용하고 싶을 때)
const {name: studentName, age: studentAge} = student;

console.log(studentName, studentAge); // kyuree 38
profile
디자인하는 Frontend Developer.

0개의 댓글