자바스크립트의 배열을 사용할 때 주의할 점

짱유경·2021년 6월 12일
2

JavaScript

목록 보기
2/3
post-thumbnail

🎫 자바스크립트에서의 배열

자바스크립트에서의 배열은 다루기 특이한 점이 몇가지 있다.
일단, 자바스크립트에서의 배열은 미리 사이즈를 할당하지 않는다. 또한 배열에는 어떤 타입의 값이라도 담을 수 있다.

배열을 생성하는 방법은 리터럴 방식네이티브 생성자를 활용하는 방법이 있다. 리터럴 방식은 일반적으로 사용할 때와 같이 var arr=[];과 같은 방식으로 선언해주는 방식을 뜻한다.

네이티브 방식은 new Array()를 사용하는 방식이다. 들어가기전, 네이티브 생성자에 대해 잠깐 알아보고 가자.

네이티브는 특정 환경에(브라우저나 클라이언트 프로그램)에 종속되지 않은 내장 객체를 말합니다. 예를 들어 window와 같은 함수는 브라우저에 종속되는 함수기 때문에 네이티브가 아니죠! Array()는 네이티브 중 하나입니다.
네이티브로 생성한 값은 원시 값을 감싼 객체 래퍼 중 하나입니다. 만약 new String("hello") 와 같은 값을 생성하면 원시값 string을 생성하는게 아니라 원시값을 감싼 객체를 생성하는 셈이죠!

new Array()

위에서 말한 네이티브 생성자를 활용해 배열을 사용하는 방식이다. new Array(배열 안에 들어갈 값)과 같이 사용한다. 출력 결과를 확인해 보면 인덱스와 값이 문제없이 매칭되어 있고, length 또한 우리가 집어넣은 인자의 갯수와 같이 2개로 나타난다.

let arr = new Array(1, 2);
console.log(arr); // [1, 2]

하지만 new Array()에는 큰 함정이 숨겨있다. 만약 인자를 한개만 넘겨준다면 어떻게 될까?

let arr = new Array(5);
console.log(arr);

아마 length는 1이고 0번 인덱스애는 5인 값을 예상했을 것이다. 하지만 실제 결과값은 아래와 같다.

빈 슬롯(undefined가 아니라 정말 빈 슬롯이다.)이 생성된다. 그것도 길이는 5개로..! 넘긴 숫자의 크기 만큼 빈 공간의 배열이 생성됨을 알 수 있다. 이러한 배열을 구멍난 배열(Sparse Array)라고 한다.

단, 항목이 하나 뿐이며 그 항목의 자료형이 숫자일 경우 아래의 arrayLength 매개변수로 간주합니다.
Array 생성자에 제공한 유일한 매개변수가 0에서 232-1 이하의 정수인 경우, length 속성이 해당 값인 새로운 JavaScript 배열을 생성합니다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Array

다행히 인자를 한개로 넘길 때 숫자가 아닌 문자열과 같은 값으로 넘기면 빈 슬롯과 공간이 생기지 않은 채로 무사히 생성된다.

배열을 사용할 때 new Array()를 사용할 이유는 크게 없다. 리터럴 방식이 작성하기 더욱 편하고, 만약 누군가 new Array()안에 인자를 한개의 숫자로 넘긴다면..! 의도하지 않은 에러가 나타날 수 있다. 😣 이 방식은 특별한 케이스가 아니라면, 사용을 지양하도록 하자..!

delete

배열의 일부 요소를 삭제할 수 있는 delete 이다. 아래와 같이 사용하면 0번 인덱스의 내용이 삭제된다. delete는 삭제를 하면 true를, 삭제하지 못하면 false를 반환한다. 존재하지 않는 속성을 삭제하려 해도 true를 리턴한다.

delete arr[0];

그러나 이 방법에는 큰 문제가 있다. delete를 사용하면 요소가 삭제되지만, 요소가 들어간 방, 인덱스는 삭제되지 않는다. 그대로 빵꾸가 나버린다. 아까 위에서 new Array()에 인자를 한개의 숫자로 넘겼을때 봤던 empty 상태와 동일한 상태인 것이다.
빵꾸가 난 배열은 명시적으로 arr[0] = undefined를 세팅한 것과는 같지 않기에 주의해야 한다. 아래 예제를 보면 delete로 구멍난 배열의 값을 찾을 경우 없다고 판단되어 if문 안의 값을 리턴하지 않지만, undefined를 할당한 값의 경우 배열 안의 원소로 존재하기 때문에 둘은 완전히 상이하다.

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];
if (3 in trees) {
    console.log("실행!");
}
// undefined
var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees[3] = undefined;
if (3 in trees) {
    console.log("실행!");
}
// 실행!

delete를 사용해 배열의 요소를 삭제하는 일 또한 지양하도록 하자. 만약 배열의 요소를 삭제하고 싶다면, splice()를 사용해 지워주도록 하자.

(객체에도 이와 같은 방식을 사용하면 안되는지 아시는분은 댓글로 알려주세요!..)

구멍난 배열 - Sparse Array

구멍난 배열을 생성하는 방법에는 new Array()delete를 사용하는 방법 외에도 몇가지 더 있다. 아래와 같이 배열의 key값을 줘도 해당 인덱스 만큼의 빈 배열이 생김을 알 수 있다.
말 그대로 "구멍이 생겼다"라는 의미로 실행되기 때문에, 사용하지 않는 메모리로 판단되어 GC에게서 구원받지도 못한다. 또 값이 없다고 취급되어 오류가 발생할 수 있기 때문에 for문으로 배열의 길이만큼 인덱스를 넣어보고, 이때 배열의 i번째 값이 있을때 코드를 실행한다는 등의 안전장치를 걸어둬야 한다.

var arr2 = ["1번방"]
arr2[500] = "500번 방";
arr2; // ["1번방", empty × 499, "500번 방"]

또는 아래와 같이 선언해도 구멍난 배열이 생성된다.

var arr = [,,,,,];
arr; // [empty × 5]

var arr = [1,2,3,4,,6];
arr; // [1, 2, 3, 4, empty, 6]

여기서 구멍난 방을 표현하는 empty라는 값은 브라우저별로 표현하는 방식이 상이하다.

유사배열

유사배열은 말 그대로 배열과 유사한 배열 (?) 이다. 배열의 메서드를 빌려쓸 수도 있고, 배열처럼 작동하기도 하는데 막상 속은 배열이 아닌것과 같은 녀석이다. 마치,,전자담배와 담배의 차이처럼 🙄

유사배열의 대표적인 종류는 문자열이 있다. 우리가 일상적으로 쓰는 let str = "칼퇴"; 요런 변수도 유사배열이다. 이외 유사배열의 종류로는 document.querySelectorAll("p")와 같이 DOM을 탐색하는 친구이다. (이 친구들은 배열과 유사한 생김새지만, NodeList라는 별개의 친구다.)

유사배열 친구들은 배열의 메서드를 빌려쓸 수 있다. 여기서 특정 메서드란 불변성을 지키는 메서드를 얘기한다. 예를들어 str[0]과 같이 문자열의 특정 번째 글자를 가져올 수 있고, concate()이나 split()같은 친구들도 잘 작동한다. 단, 문자열에서 a[1]과 같이 특정 문자를 접근하는 형태는 모든 자바스크립트 엔진에서 유효하지는 않기에 조심해야 한다.

문자열은 기본적으로 primitive type중 하나이다. 그말은 불변성을 지키는 타입이라는 말이다. 그래서 불변성과 관련된 메서드밖에 사용하지 못한다.

유사배열을 실제 배열처럼 쓰고싶으면 ES6의 Array.from()을 쓰도록 하자.

Array.from() 메서드는 유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사해 새로운Array 객체를 만듭니다.

📃 정리

  1. 자바스크립트에서 배열을 생성하는 건 리터럴(var a = [];)과 네이티브 생성자(new Array())방식이 있다.
  2. 이때 new Array()방식을 쓸 때 인자를 정수 형태로 한개만 생성하면 arrayLength로 취급 되어 정수값만큼 길이를 가진 빈 배열이 생성된다.
  3. delete로 배열의 원소를 삭제하는 경우에도 위와 같이 빈 공간이 생긴다.
  4. 이러한 배열을 구멍난 배열이라 부르며, 이러한 구멍난 배열은 명시적으로 undefined를 쓴 것과는 다르다.
  5. 유사배열중 대표적인 예는 문자열이다. 문자열은 배열의 메서드를 빌려 사용할 수 있지만 primitive type이므로 불변적인 메서드만 빌려쓸 수 있다. 유사배열을 완전한 배열처럼 쓰고싶을땐 Array.from()을 쓰자!

🔗 Refer

You Don't Know JS 1권 - 타입과 문법, 스코프와 클로저
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/Array
https://www.freecodecamp.org/news/sparse-and-dense-arrays-in-javascript/

0개의 댓글