[자바스크립트 딥다이브] 27장 배열(1)

Bor·2022년 1월 7일
0

JS딥다이브

목록 보기
19/24

서론 : 왜 공부하는가?

일단 학기 중에 파이썬과 JS를 병행하면서 헷갈릴 때도 많았고 그래서 손코딩으로 과제를 낼 때 len() 대신에 .length를 과감하게 질러버린 적도 있었다. 그런 면에서 자료구조 B+은 정말 놀라운 성적. 배열의 메서드를 조금 더 많이 다루고 특히나 언제까지 for문을 쓸거야! forEach 등에 대해서도 배열을 공부하면서 익혀보자.

27.1 배열이란?

배열은 여러 개의 값을 순차적으로 나열한 자료구조. 배열이 가지고 있는 값을 요소(elements)라고 부른다. 원시값은 물론 객체, 함수, 배열 등 모든 값은 배열의 요소가 될 수 있다.

  • 자신의 위치를 나타내는 0이상의 정수인 인덱스(index)를 갖는다.
  • 배열은 요소의 개수, 즉 배열의 길이를 나타내는 length 프로퍼티를 갖는다.
  • 배열은 위처럼 length, 인덱스 프로퍼티를 갖기 때문에 for문을 통해서 순차적으로 요소에 접근 가능
  • 배열이라는 타입은 존재하지 않는다. 배열도 객체다.

배열은 객체지만 일반 객체와는 구별되는 독특한 특징이 있다

구분객체배열
구조프로퍼티 키와 프로퍼티 값인덱스와 요소
값의 참조프로퍼티 키인덱스
값의 순서XO
length프로퍼티XO
  • 일반 객체와 배열을 구분하는 가장 명확한 차이는 값의 순서와 length프로퍼티.
  • 배열의 장점은 순차적으로 접근 할수도, 역순으로, 특정 위치부터 접근도 가능하다는 점.

27.2 자바스크립트의 배열은 배열이 아니다

  • 학기 중 배운 것처럼 자료구조에서 말하는 배열은 동일한 크기의 메모리 공간이 빈틈없이 연속적으로 나열된 자료구조이며 이러한 배열을 밀집 배열(dense array)라 부른다.
  • 반면에 희소 배열(sparse array)은 메모리 공간이 동일한 크기가 아니어도 되며, 연속적이지 않을 수도 있다.
  • 자바스크립트 배열은 엄밀히 말하면 일반적인 배열이 아니며, 배열의 동작을 흉내낸 특수한 객체.
  • 자바스크립트 배열의 요소는 사실 프로퍼티 값이다.
  • 일반적인 배열은 인덱스로 요소에 빠르게 접근할 수 있다. 그러나 특정 요소 검색, 삽입 삭제는 효율적이지 않다
  • 자바스크립트는 해시 테이블로 구현된 객체. 접근은 느릴 수밖에 없는 단점이 있지만 삽입 또는 삭제, 검색은 일반적인 배열보다 빠르다.

27.3 length 프로퍼티와 희소 배열

length 프로퍼티는 요소의 개수 === 가장 큰 인덱스에 +1 한 값과 동일하다. length 프로퍼티의 값은 요소를 추가하거나 삭제하면 자동으로 갱신된다.

  • length의 현재 값보다 작은 숫자를 할당하면 배열의 길이가 줄어든다.
  • 주의할 것은 큰 숫자를 할당하는 경우. length의 값은 변경되도 실제 배열의 길이가 늘어나지는 않는다. 메모리 공간을 확보하지 않으며 빈 요소를 생성하지도 않는다
  • JS는 이렇게 희소 배열을 문법적으로 허용한다. 그러나 의도적으로 쓸 일은 없을 것이다. 최적화가 잘 되어 있는 모던 JS엔진은 일반적인 의미의 배열처럼 연속된 메모리 공간을 확보하는 것으로 알려져 있다

27.4 배열 생성

27.4.1 배열 리터럴

다양한 생성 방식이 있으며 가장 일반적이고 간편한 방식은 리터럴을 사용하는 것이다.

  • 배열 리터럴은 0 개 이상의 요소를 쉼표로 구분하여 대괄호로 묶는다.
  • 배열 리터럴에 요소를 하나도 추가하지 않으면 length 프로퍼티 값이 0인 빈 배열
  • 리터럴에 요소를 생략하면 희소 배열이 생성

27.4.2 Array 생성자 함수

Array 생성자 함수는 전달된 인수의 개수에 따라 다르게 동작하므로 주의가 필요

  • 전달된 인수가 1개인 경우 length 프로퍼티 값이 인수인 배열을 생성한다
  • 이 때 배열은 희소 배열. length 프로퍼티 값은 0이 아니지만 실제로 배열의 요소는 존재하지 않는다
  • 전달된 인수가 2개 이상, 숫자면 인수를 요소로 갖는 배열을 생성한다

근데 이렇게 생성할 때가 있을까..?

27.4.3 Array of

ES6에 도입된 Array.of 메서드는 전달된 인수를 요소로 갖는 배열을 생성. 생성자 함수와 다르게 전달된 인수가 1개여도 요소로 갖는 배열을 생성

27.4.4 Array.from

ES6에서 도입된 Array.from 메서드는 유사 배열 객체 또는 이터러블 객체를 인수로 전달받아 배열로 변환하여 반환.

  • Array.from을 상요하면 두 번째 인수로 전달한 콜백함수를 통해 값을 만들면서 요소를 채울 수 있다. Array.from 메서드는 두 번째 인수로 전달한 콜백 함수에 첫 번째 인수에 의해 생성된 배열의 요소값과 인덱스를 순차적으로 전달하면서 호출하고, 콜백 함수의 반환값으로 구성된 배열을 반환

27.5 배열 요소 참조

요소를 참조할 때는 대괄호 []를 사용. 안에는 인덱스가 와야하며 값을 참조할 수 있다는 의미에서 객체의 프로퍼티 키와 같은 역할을 한다.

  • 존재하지 않는 요소에 접근하면 undefined가 반환된다.
  • 왜냐하면 배열은 사실 인덱스를 나타내는 문자열을 프로퍼티 키로 갖는 객체이므로!

27.6 배열 요소의 추가와 갱신

객체에 프로퍼티를 동적으로 추가할 수 있는 것처럼 배열에도 요소를 동적으로 추가할 수 있다. 존재하지 않는 인덱스를 써서 할당하면 새로운 요소가 추가됨.

  • 인덱스는 요소의 위치를 나타내므로 반드시 0이상의 정수를 사용해야. 만약 정수 이외의 값을 인덱스처럼 사용하면 요소가 생성되는 것이 아니라 프로퍼티가 생성된다(파이썬처럼 -1 요런거 안 됨)
  • 이때 추가된 프로퍼티는 length의 값에 영향을 주지 않는다

27.7 배열 요소의 삭제

얘는 객체이므로 특정 요소를 삭제하기 위해서 delete를 사용할 수 있다. 근데 객페의 프로퍼티를 삭제한다.

  • 🙅‍♂ : delete 연산자는 객체의 프로퍼티를 삭제함. 따라서 위의 delete는 프로퍼티 키가 1인 프로퍼티를 삭제. 이때 배열은 희소 배열이 되며 length 프로퍼티 값은 변하지 않는다. 그래서 희소배열로 만들어 버리는 delete 연산자는 사용하지 말자!
  • 희소 배열을 만들지 않으면서 배열의 특정 요소를 완전히 삭제하려면 Array.prototype.splice 메서드를 사용한다.

27.8 배열 메서드

배열 메서드는 결과물을 봔환하는 패턴이 두 가지!

  • 원본 배열(배열 메서드를 호출한 배열, this가 가리키는 객체)을 직접 변경하는 메서드
  • 원본 배열을 변경하지 않고 새로운 배열을 생성하여 반환하는 메서드가 있다.
  • push:push 메서드는 원본 배열을 변경

  • concat은 직접 변경하지 않고 새로운 배열을 생성해서 반환

초창기 배열 메서드는 원본 배열을 직접 변경하는 경우가 많다. 직접 변경하는 경우 부수효과가 있으므로 사용 시주의! 따라서 가급적 원본 배열을 직접 변경하지 않는 메서드를 사용하는 편이 좋다.

27.8.1 Array.isArray

Array.isArray도 of와 from처럼 Array 생성자 함수의 정적 메서드이며 전달된 인수가 배열이면 true, 아니면 false를 반환.

27.8.2 Array.prototype.indexOf

indexOf 메서드는 원본 배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환

  • 원본 배열에 인수로 전달한 요소와 중복되는 요소가 여러 개 있다면 첫 번째로 검색된 요소의 인덱스
  • 원본 배열에 인수로 전달한 요소가 존재x, -1을 반환한다
  • indexOf 메서드는 배열에 특정 요소가 존재하는지 확인할 때 유용하다
  • indexOf 메서드 대신 ES7에서 도입된 includes 메서드를 사용하면 가독성이 더 좋다.

27.8.3 Array.prototype.push

마지막 요소로 추가하고 변경된 length 값을 반환, 원본 배열을 직접 변경한다.

  • push 메서드는 성능 면에서 좋지 않다. 마지막 요소로 추가할 요소가 하나 뿐이라면 push를 사용하지 않고 length 프로퍼티를 사용해서 배열의 마지막 요소를 직접 추가할 수도 있으며, push 메서드보다 빠르다.
  • push 메서드는 원본 배열을 직접 변경하는 부수 효과가 있다. 따라서 push 메서드보다는 ES6 스프레드 문법을 사용하는 편이 좋다. 스프레드 문법을 사용하면 함수 호출없이 마지막에 요소를 추가할 수 있으며 부수 효과도 없다.

27.8.4 Array.prototype.pop

pop 메서드는 원본 배열에서 마지막 요소를 제거하고 반환. (파이썬과 동일)

  • 스택도 구현 가능!

27.8.5 Array.prototype.unshift

  • unshift 메서드는 인수로 전달 받은 모든 값을 원본 배열의 선두 요소로 추가 + 변경된 length 프로퍼티 값을 반환.
  • 🙋 얘두 원본 배열을 직접 변경하는 부수효과가 있다. 그래서 ES6 스프레드 문법을 쓰세요.
  • 반대로 .shift()는 첫번째 요소를 제거하고 제거한 요소를 반환.
  • 그리고 이후에 나올 concat 메서드로 대체할 수 있다.

TIL

  • 시간이 조금 더 걸려도 상관 없다. 예제 고.대.로 타이핑하지 말고 응용해서 내가 한 번 만들어보자. 타자연습은 충분히 했다!
  • 희소배열이라는 개념! 배열도 객체이므로 접근 시간과 왜 이렇게 만들게 되었는지 알게 되었다.그리고 이로 인해서 delete와 splice의 차이를 알게 되었다
  • 배열과 메서드 : push와 concat의 차이! 추가할 때 고민 없이 사용하곤 했는데 차이를 알고 나니 원본 배열을 바꿔도 되는 or 안 되는 상황에 따라 구분하며 사용해야겠다
  • isArray: 프로그래머스 스터디를 하면서 type 검정을 할 때 사용했었는데 드디어 만났다. 그 때 피드백으로 이걸 사용하라고 하셨는데 다시 가서 코드를 보면서 맥락을 짚어봐야지
  • indexOf, inclues : 후자가 훨씬 가독성이 좋다. 영어 문장 읽듯이 읽힌다. 근데 둘의 차이점은?
  • 스프레드 문법도 그냥 사용하지 말자. 장점: 호출 없이 마지막에 요소를 추가 가능

0개의 댓글