javascript 26강 배열 및 고차함수 1


JavaScript 26강 예습

  • 26강 : 배열

    • 배열이란?

      • 객체 vs 배열
    • JS 배열은 배열이 아니다.

    • length 프로퍼티와 희소 배열

    • 배열 생성

      1. 배열 리터럴

      2. Array 생성자 함수

        • Array.of

        • Array.from

        • 유사 배열 객체와 이터러블 객체

    • 배열 요소의 참조

    • 배열 요소의 추가와 갱신

    • 배열 요소의 삭제

    • 배열 메소드

      1. Array.isArray
      2. Array.prototype.push
      3. Array.prototype.pop
      4. Array.prototype.unshift
      5. Array.prototype.shift
      6. pop과 shift를 이용한 queqe 구현
      7. pop과 push를 이용한 stack 구현
      8. Array.prototype.concat
      9. Array.prototype.splice
      10. Array.prototype.slice
      11. Array.prototype.indexOf
      12. Array.prototype.join
      13. Array.prototype.reverse
      14. Array.prototype.fill
      15. Array.prototype.includes
    • 고차 함수



26강 - 1

배열

배열이란?

순서가 있는 값들의 리스트를 의미한다.

하나의 변수에 여러 개의 값을 저장할 수 있는 장점이 있다.

배열이 가지고 있는 값을 요소(element)라 부른다.

JS에서 값으로 인정하는 모든 것은 배열의 요소가 될 수 있다.

자바스크립트에서 배열이라는 타입은 존재하지 않는다.

배열은 객체이다.

1
typeof arr // -> object

배열은 배열리터럴 과 Array 생성자 함수로 생성 할 수 있다.

  • 배열리터럴

    1
    const arr = ['apple', 'banana', 'orange'];
  • Array 생성자

    1
    2
    const arr = new Array();
    arr = ['apple', 'banana', 'orange'];

배열의 생성자 함수는 Array이며 배열의 프로토타입 객체는 Array.prototype이다.

Array.prototype은 배열을 위한 빌트인 메소드 들을 제공한다.


객체 vs 배열

구분 객체 배열
구조 프로퍼티 키와 프로퍼티 값 인덱스와 요소
값의 참조 프로퍼티 키 인덱스
값의 순서 x
length 프로퍼티 x

JS 배열은 배열이 아니다.

일반적인 배열이라는 개념은 동일한 크기의 메모리공간이 빈틈없이 연속적으로 나열된 자료 구조를 말한다. 일반적인 배열의 요소들은 하나의 타입으로 통일되어 서로 연속적으로 인접하고 있는 밀집 배열(Dense array)이다.

1
2
검색 대상 요소의 메모리 주소 = 배열의 시작 메모리 주소 + 인덱스 * 요소의 바이트 수
- 인덱스가 2인 요소에 메모리 주소 : 1000 + 2 * 8 = 1016

밀집 배열의 장점 : 한번의 연산으로 모든 요소에 접근이 가능하다. 효율적이면 고속으로 동작함.
밀집 배열의 단점 : 특정 값 탐색 시 처음부터 선행 - 시간복잡도 O(n), 배열 삭제 및 삽입시 요소를 이동시켜야 함.


자바스크립트의 배열은 요소를 위한 동일한 크기의 메모리를 할당해주지 않으며 연속적으로 나열하지도 않는다. 이러한 배열을 희소 배열(sparse array)이라 한다.

1
2
3
4
5
6
7
8
9
10
11
const arr = [1, 2, 3];

console.log(Object.getOwnPropertyDescriptors(arr));
/*
{
'0': { value: 1, writable: true, enumerable: true, configurable: true },
'1': { value: 2, writable: true, enumerable: true, configurable: true },
'2': { value: 3, writable: true, enumerable: true, configurable: true },
length: { value: 3, writable: true, enumerable: false, configurable: false }
}
*/

위 예제를 보면 배열 arr은 각각 프로퍼티로 0 , 1 , 2 를 각각 가지고 있다. 즉 배열은 객체이다.

JS에서 배열은 일반적인 배열을 흉내낸 객체이다.

JS 배열의 장점 : 배열 요소를 삽입하거나 삭제하는 경우에는 해시 테이블을 따라 가기 때문에 일반 배열보다 빠르다.
JS 배열의 단점 : 해시 테이블로 구현된 객체이므로 인덱스 자체로 배열 요소에 접근시 일반적인 배열보다 느린 구조다.

따라서 JS에서는 이러한 구조적 단점을 보안하고자 배열을 객체와 달리하여 속도를 향상시켰다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const arr = [];

console.time('Array Performance Test');

for (let i = 0; i < 10000000; i++) {
arr[i] = i;
}
console.timeEnd('Array Performance Test');
// 약 340ms

const obj = {};

console.time('Object Performance Test');

for (let i = 0; i < 10000000; i++) {
obj[i] = i;
}

console.timeEnd('Object Performance Test');
// 약 600ms

객체 obj배열 arr 보다 성능면에서 2배정도 차이가 났다.

객체 obj에게 숫자를 프로퍼티키로 주면 ''는 안붙지만 내부에서 암묵적으로 문자열로 변환된다.


length 프로퍼티와 희소 배열

length 프로퍼티는 요소의 개수, 즉 배열의 길이를 나타내는 정수를 값으로 갖는다. length 프로퍼티의 값은 빈 배열일 경우, 0이며 빈 배열이 아닐 경우, 가장 큰 인덱스에 1을 더한 것과 같다.

1
2
[].length        // -> 0
[1, 2, 3].length // -> 3

배열에서 사용할 수 있는 가장 작은 인덱스는 0이며 가장 큰 인덱스는 232 – 2(4,294,967,294)이다.

length 프로퍼티의 값은 배열에 요소를 추가하거나 삭제하면 자동 갱신된다.

배열의 length에 임의의 숫자 값을 명시적으로 할당할 수도 있다.

현재 length 프로퍼티 값보다 작은 숫자 값을 할당하면 배열의 길이가 줄어든다.

1
2
3
4
5
6
7
const arr = [1, 2, 3, 4, 5];

// length 프로퍼티에 현재 length 프로퍼티 값보다 작은 숫자 값을 할당
arr.length = 3;

// 배열의 길이가 줄어든다.
console.log(arr); // [1, 2, 3]

만약 length에 프로퍼티 값보다 큰 값을 할당하면 length 프로퍼티 값은 변경되지만 실제로 배열의 길이가 늘어나지는 않는다.

1
2
3
4
5
6
7
8
const arr = [1];

// length 프로퍼티에 현재 length 프로퍼티 값보다 큰 숫자 값을 할당
arr.length = 3;

// length 프로퍼티 값은 변경되지만 실제로 배열의 길이가 늘어나지는 않는다.
console.log(arr.length); // 3
console.log(arr); // [1, empty × 2] 즉, arr[1]과 arr[2]에는 값이 존재하지 않는다.

값이 없이 비어있는 요소를 위해 메모리 공간을 확보하지 않으며 빈 요소를 생성하지도 않는다.

1
2
3
4
5
6
7
console.log(Object.getOwnPropertyDescriptors(arr));
/*
{
'0': { value: 1, writable: true, enumerable: true, configurable: true },
length: { value: 3, writable: true, enumerable: false, configurable: false }
}
*/

위와 같이 배열의 요소가 연속적으로 위치 하지 않고 땜방 마냥 비어있는 배열을 희소배열이라 한다.

JS는 희소 배열을 문법적으로 허용하고 있으며 앞 , 중간 , 뒤 부분 어느곳도 비울 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 희소 배열
const sparse = [, 2, , 4];

// 희소 배열의 length 프로퍼티 값은 요소의 개수와 일치하지 않는다.
console.log(sparse.length); // 4
console.log(sparse); // [empty, 2, empty, 4]

// 배열 sparse에는 인덱스가 0, 2인 요소가 존재하지 않는다.
console.log(Object.getOwnPropertyDescriptors(sparse));
/*
{
'1': { value: 2, writable: true, enumerable: true, configurable: true },
'3': { value: 4, writable: true, enumerable: true, configurable: true },
length: { value: 4, writable: true, enumerable: false, configurable: false }
}
*/

희소 배열은 length와 배열 요소의 개수가 일치하지 않는다. 희소 배열의 length는 실제 배열의 요소 개수보다 언제나 크다.


배열 생성

배열 리터럴

배열 리터럴은 0개 이상의 요소를 쉼표로 구분하여 대괄호([])로 묶는다.

1
2
3
4
5
6
7
const arr = [];
console.log(arr.length); // 0

const arr = [1, , 3]; // 희소 배열
console.log(arr.length); // 3
console.log(arr); // [1, empty, 3]
console.log(arr[1]); // undefined

arr[1]이undefined인 이유는 실제 객체인 arr에 프로퍼티 키가 ‘1’인 프로퍼티가 존재하지 않기 때문이다.


Array 생성자 함수

Array 생성자 함수를 통해 배열을 생성할 수 있다.

Array 생성자 함수는 전달된 인수의 개수에 따라 다르게 동작한다.

  • 전달된 인수가 1개이고 숫자인 경우, 인수를 length 프로퍼티의 값으로 갖는 배열을 생성한다.
1
2
3
4
const arr = new Array(10);

console.log(arr); // [empty × 10]
console.log(arr.length); // 10

이때 생성된 배열은 희소 배열이다. length 프로퍼티의 값은 0이 아니지만 실제로 배열의 요소는 존재하지 않는다.

1
2
3
4
console.log(Object.getOwnPropertyDescriptors(arr));
/*
{ length: { value: 10, writable: true, enumerable: false, configurable: false } }
*/

전달된 인수는 0 ~ 232-1(4294967295) 사이의 정수이어야 한다. 전달된 인수가 범위를 벗어나면 RangeError가 발생한다.

1
2
3
4
5
// 전달된 인수가 음수이면 에러가 발생한다.
new Array(-1); // RangeError: Invalid array length

// 배열에는 요소를 최대 4294967295개 갖을 수 있다.
new Array(4294967296); // RangeError: Invalid array length
  • 전달된 인수가 없는 경우, 빈 배열을 생성한다. 즉, 배열 리터럴 []과 같다.
1
2
3
const empty = new Array();

console.log(empty); // []
  • 전달된 인수가 2개 이상이거나 숫자가 아닌 경우, 인수를 요소로 갖는 배열을 생성한다.
1
2
3
4
5
6
7
8
9
// 전달된 인수가 1개이지만 숫자가 아니면 인수를 요소로 갖는 배열을 생성한다.
const arr1 = new Array({});

console.log(arr1); // [{}]

// 전달된 인수가 2개 이상이면 인수를 요소로 갖는 배열을 생성한다.
const arr2 = new Array(1, 2, 3);

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

Array 생성자 함수는 new 연산자와 호출하지 않더라도, 즉 함수로 호출하더라도 배열을 생성하는 생성자 함수로 동작한다.

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

Array.of

​ ES6에서 도입됨. 전달된 인수를 요소로 갖는 배열을 생성함.

Array.of는 Array 생성자 함수와 다르게 전달된 인수가 1개이고 숫자이더라도 인수를 요소로 갖는 배열을 생성한다.

1
2
3
4
5
6
7
8
9
// 전달된 인수가 1개이고 숫자이더라도 인수를 요소로 갖는 배열을 생성한다.
const arr1 = Array.of(1);
console.log(arr1); // // [1]

const arr2 = Array.of(1, 2, 3);
console.log(arr2); // [1, 2, 3]

const arr3 = Array.of('string');
console.log(arr3); // 'string'

Array.from

​ ES6에서 도입됨. 유사 배열 객체 또는 이터러블 객체를 변환하여 새로운 배열을 생성함.

정적 메소드이다.

1
2
3
4
5
6
7
// 문자열은 이터러블이다.
const arr1 = Array.from('Hello');
console.log(arr1); // [ 'H', 'e', 'l', 'l', 'o' ]

// 유사 배열 객체를 새로운 배열을 변환하여 반환한다.
const arr2 = Array.from({ length: 2, 0: 'a', 1: 'b' });
console.log(arr2); // [ 'a', 'b' ]

Array.from을 사용하면 두번째 인수로 전달한 함수를 통해 값을 만들면서 요소를 채울 수 있다.

Array.from({ length: 길이값 }, function (길이값, 현재값) { return 현재값; });

1
2
3
4
// Array.from의 두번째 인수로 배열의 모든 요소에 대해 호출할 함수를 전달할 수 있다.
// 이 함수는 첫번째 인수에 의해 생성된 배열의 요소값괴 인덱스를 순차적으로 전달받아 호출된다.
const arr3 = Array.from({ length: 5 }, function (v, i) { return i; });
console.log(arr3); // [ 0, 1, 2, 3, 4 ]

유사 배열 객체와 이터러블 객체

유사배열 객체 : 배열처럼 인덱스로 프로퍼티 값에 접근이 가능하다. length 프로퍼티를 갖는 객체
legth 프로퍼티로 인해 반복문으로 순회가 가능한 구조다.

이터러블 객체 : Symbol.iterator 메소드를 구현하여 for…of 문으로 순회할 수 있으며 Spread 문법의 대상으로 사용할 수 있는 객체를 말한다.
ES6에서 제공하는 빌트인 이터러블은 Array, String, Map, Set, DOM data structure(NodeList, HTMLCollection), Arguments 등


배열 요소의 참조

배열 요소를 참조할 때에는 대괄호([]) 표기법을 사용한다.

희소 배열의 존재하지 않는 요소를 참조하면 undefined가 반환된다.

배열은 사실 인덱스를 프로퍼티 키로 갖는 객체이다.

따라서 존재하지 않는 프로퍼티 키로 객체의 프로퍼티에 접근했을 때 undefined를 반환하는 것처럼 배열도 존재하지 않는 요소를 참조하면 undefined가 반환한다.


배열 요소의 추가와 갱신

객체에 프로퍼티를 동적으로 추가할 수 있는 것처럼 배열에도 요소를 동적으로 추가할 수 있다.

요소가 존재하지 않는 인덱스의 배열 요소에 값을 할당하면 새로운 요소가 추가된다. length 프로퍼티 값은 자동 갱신된다.

1
2
3
4
5
6
const arr = [0, 1];
// 현재 배열의 length 프로퍼티 값보다 큰 인덱스로 새로운 요소를 추가하면 희소 배열이 된다.
arr[100] = 100;

console.log(arr); // [0, 1, empty × 98, 100]
console.log(arr.length); // 101
1
2
3
4
5
6
7
8
9
// 명시적으로 값을 할당하지 않은 요소는 생성되지 않는다.
console.log(Object.getOwnPropertyDescriptors(arr));
/*
{
'0': { value: 0, writable: true, enumerable: true, configurable: true },
'1': { value: 1, writable: true, enumerable: true, configurable: true },
'100': { value: 100, writable: true, enumerable: true, configurable: true },
length: { value: 101, writable: true, enumerable: false, configurable: false }
*/

요소 값 갱신 : 존재하는 요소에 값을 재할당시 요소값이 갱신된다.

1
2
3
4
// 요소값의 갱신
arr[1] = 10;

console.log(arr); // [0, 10, empty × 98, 100]

인덱스는 요소의 위치를 나타내므로 반드시 0 이상의 정수(또는 정수 형태의 문자열)를 사용하여야 한다. 만약 정수 이외의 값을 인덱스처럼 사용하면 요소가 생성되는 것이 아니라 프로퍼티가 생성된다. 이때 추가된 프로퍼티는 length 프로퍼티의 값에 영향을 주지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const arr = [];

// 배열 요소의 추가
arr[0] = 1;
arr['1'] = 2; // 문자열 '1'을 숫자 1로 암묵적 타입 변환

// 프로퍼티 추가
arr['foo'] = 3;
arr[1.1] = 4;

console.log(arr); // [1, 2, foo: 3, 1.1: 4]

// 프로퍼티는 length에 영향을 주지 않는다.
console.log(arr.length); // 2 - arr[0] , arr[1]

배열 요소의 삭제

배열의 특정 요소를 삭제하기 위해 delete 연산자를 사용할 수 있다.

(delete 연산자는 프로퍼티 키만 삭제하므로 length에는 영향을 주지 않는다. )

length에 영향을 주고 싶다면 배열명.shift() 혹은 배열명.splice(인덱스위치, 부터 개수)를 이용한다.

1
2
3
4
5
6
7
8
const arr = [1, 2, 3];

// 배열 요소의 삭제
delete arr[1];
console.log(arr); // [1, empty, 3]

// 프로퍼티는 length에 영향을 주지 않는다.
console.log(arr.length); // 3

배열의 특정 요소를 완전히 삭제하여 length 프로퍼티 값에도 반영되게 하기 위해서는 Array.prototype.splice 메소드를 사용한다.(shift() 혹은 pop()도 영향을 준다.)

1
2
3
4
5
6
const arr = [1, 2, 3];

// Array.prototype.splice(삭제를 시작할 인덱스, 삭제할 요소수)
// arr[1]부터 1개의 요소를 제거
arr.splice(1, 1);
console.log(arr); // [1, 3]

배열 메소드

Array.prototype에는 배열을 다룰 때 필요한 메소드를 제공. ( 2가지 타입이 존재 )

  1. 배열에는 원본 배열을 직접 변경하는 메소드(mutator method)
  2. 원본 배열을 직접 변경하지 않고 새로운 배열을 생성하여 반환하는 메소드(accessor method)

Array.isArray

  • 정적 메소드
  • Array.isArray는 주어진 인수가 배열이면 true, 배열이 아니면 false를 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// true
Array.isArray([]);
Array.isArray([1, 2]);
Array.isArray(new Array());

// false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(1);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);

Array.prototype.push (스택/큐 구현 용이)

  • 원본 배열 직접 변경
  • 원본 배열에 전달받은 인수를 마지막 요소로 추가함. length 영향 o
  • 변경된 length 값을 반환함.
  • length값으로 직접 추가하는 것이 push() 보다 성능이 좋음.
  • spread 문법으로 대체 가능
1
2
3
4
5
6
7
8
9
10
11
const arr = [1, 2];

// arr.push(3)와 동일한 처리를 한다. 이 방법이 push 메소드보다 빠르다.
arr[arr.length] = 3;

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

const newArr = [...arr, 4];
// arr.push(4);

console.log(newArr); // [1, 2, 3, 4]

Array.prototype.pop (스택 구현 용이)

  • 원본 배열 직접 변경
  • 마지막 요소를 제거함. length 영향 o
  • 제거한 요소를 반환함. (빈 배열이라면 undefined)
1
2
3
4
5
6
7
8
const arr = [1, 2];

// 원본 배열에서 마지막 요소를 제거하고 제거한 요소를 반환한다.
let result = arr.pop();
console.log(result); // 2

// pop 메소드는 원본 배열을 직접 변경한다.
console.log(arr); // [1]

Array.prototype.unshift

  • 원본 배열 직접 변경
  • 인수로 전달 받은 모든 값을 원본 배열의 맨 앞에 추가함. length 영향 o
  • 변경된 length 값을 반환함.
  • spread 문법으로 대체 가능.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const arr = [1, 2];

// 인수로 전달받은 모든 값을 원본 배열의 선두에 요소로 추가하고 변경된 length 값을 반환한다.
let result = arr.unshift(3, 4);
console.log(result); // 4

// unshift 메소드는 원본 배열을 직접 변경한다.
console.log(arr); // [3, 4, 1, 2]

// ES6 Spread 문법
const newArr = [3, ...arr];
// arr.unshift(3);

console.log(newArr); // [3, 4, 1, 2]

Array.prototype.shift (큐 구현 용이)

  • 원본 배열 직접 변경
  • 첫번째 요소를 제거함. length 영향 o
  • 제거한 요소를 반환함. (빈 배열이라면 undefined)
1
2
3
4
5
6
7
8
const arr = [1, 2];

// 원본 배열에서 첫번째 요소를 제거하고 제거한 요소를 반환한다.
let result = arr.shift();
console.log(result); // 1

// shift 메소드는 원본 배열을 직접 변경한다.
console.log(arr); // [2]

pop과 shift를 이용한 queqe 구현

객체로 큐(FIFO) 선입선출 자료구조 구현.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const Queue = (function () {
function Queue(array = []) {
if (!Array.isArray(array)) {
throw new TypeError(`${array} is not an array.`);
}
this.array = array;
}

// 큐의 가장 마지막에 데이터를 밀어 넣는다.
Queue.prototype.push = function (value) {
return this.array.push(value);
};

// 큐의 가장 처음 데이터, 즉 가장 먼저 밀어 넣은 데이터를 꺼낸다.
Queue.prototype.shift = function () {
return this.array.shift();
};

return Queue;
}());

const queue = new Queue([1, 2]);
console.log(queue); // [1, 2]

queue.push(3);
console.log(queue); // [1, 2, 3]

queue.shift(); // -> 1
console.log(queue); // [2, 3]

pop과 push를 이용한 stack 구현

객체로 스택(LIFO) 후입선출 자료구조 구현.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const Stack = (function () {
function Stack(array = []) {
if (!Array.isArray(array)) {
throw new TypeError(`${array} is not an array.`);
}
this.array = array;
}

// 스택의 가장 마지막에 데이터를 밀어 넣는다.
Stack.prototype.push = function (value) {
return this.array.push(value);
};

// 스택의 가장 마지막 데이터, 즉 가장 나중에 밀어 넣은 최신 데이터를 꺼낸다.
Stack.prototype.pop = function () {
return this.array.pop();
};

return Stack;
}());

const stack = new Stack([1, 2]);
console.log(stack); // [1, 2]

stack.push(3);
console.log(stack); // [1, 2, 3]

stack.pop(); // -> 3
console.log(stack); // [1, 2]

Array.prototype.concat

  • 배열의 마지막 요소로 추가한 새로운 배열을 반환.
  • 원본 배열은 유지.
  • 인수로 전달한 값이 배열인 경우, 배열을 해체하여 새로운 배열 요소로 추가함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const arr1 = [1, 2];
const arr2 = [3, 4];

// 배열 arr2를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열을 반환
// 인수로 전달한 값이 배열인 경우, 배열을 해체하여 새로운 배열의 요소로 추가한다.
let result = arr1.concat(arr2);
console.log(result); // [1, 2, 3, 4]

// 숫자를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열을 반환
result = arr1.concat(3);
console.log(result); // ["1, 2, 3]

// 배열 arr2와 숫자를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열을 반환
result = arr1.concat(arr2, 5);
console.log(result); // [1, 2, 3, 4, 5]

// 원본 배열은 변경되지 않는다.
console.log(arr1); // [1, 2]

concat을 이용한 pushunshift 대체가 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const arr1 = [3, 4];

// unshift 메소드는 원본 배열을 직접 변경한다.
arr1.unshift(1, 2);
console.log(arr1); // [1, 2, 3, 4]

// push 메소드는 원본 배열을 직접 변경한다.
arr1.push(5, 6);
console.log(arr1); // [1, 2, 3, 4, 5, 6]

// unshift와 push 메소드는 concat 메소드로 대체할 수 있다.
const arr2 = [3, 4];

// concat 메소드는 원본 배열을 변경하지 않고 새로운 배열을 반환한다.
// arr1.unshift(1, 2)를 아래와 같이 대체할 수 있다.
let result = [1, 2].concat(arr2);
console.log(result); // [1, 2, 3, 4]

// arr1.push(5, 6)를 아래와 같이 대체할 수 있다.
result = result.concat(5, 6);
console.log(result); // [1, 2, 3, 4, 5, 6]

concat은 인수로 받은 배열을 해체하여 새로운 배열로 조합하지만, push,unshift는 배열 자체를 그냥 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const arr1 = [3, 4];

// unshift와 push 메소드는 인수로 전달받은 배열을 그대로 원본 배열의 요소로 추가한다
arr1.unshift([1, 2]);
arr1.push([5, 6]);
console.log(arr1); // [[1, 2], 3, 4,[5, 6]]

const arr2 = [3, 4];

// concat 메소드는 인수로 전달받은 배열을 해체하여 새로운 배열의 요소로 추가한다
let result1 = [1, 2].concat(arr2);
result1 = result1.concat([5, 6]);

console.log(result1); // [1, 2, 3, 4, 5, 6]

//concat 메소드는 ES6의 Spread 문법으로 대체할 수 있다.
let result2 = [1, 2].concat([3, 4]);
console.log(result2); // [1, 2, 3, 4]

// concat 메소드는 ES6의 Spread 문법으로 대체할 수 있다.
let result3 = [...[1, 2], ...[3, 4]];
console.log(result3); // [1, 2, 3, 4]

concat 메소드는 ES6의 Spread 문법으로 대체할 수 있다.


Array.prototype.splice

  • 원본 배열 직접 변경
  • 중간에 요소를 추가하거나 제거하는 경우 사용.
  • 제거한 요소들을 반환함.
  • 3개의 매개변수를 가짐
    1. start : 원본 배열의 요소를 제거하기 시작할 인덱스이다. start 만을 지정시 start부터 뒤는 모두 제거한다.
    2. deleteCount : 원본 배열의 요소를 제거하기 시작할 인덱스인 start부터 제거할 요소의 개수이다. deleteCount가 0인 경우, 아무런 요소도 제거되지 않는다. (옵션)
    3. items : 제거한 위치에 삽입될 요소들의 목록이다. 생략할 경우, 원본 배열에서 지정된 요소들을 제거만 한다. (옵션)
1
2
3
4
5
6
7
8
9
const arr = [1, 2, 3, 4];

// 원본 배열의 인덱스 1부터 2개의 요소를 제거하고 그 자리에 새로운 요소 10, 30을 삽입한다.
const result = arr.splice(1, 2, 20, 30);

// 제거한 요소가 배열로 반환된다.
console.log(result); // [2, 3]
// splice 메소드는 원본 배열을 직접 변경한다.
console.log(arr); // [1, 20, 30, 4]

Array.prototype.slice

  • 원본 배열은 유지.
  • 인수로 전달된 범위의 요소들을 복사하여 반환한다.
  • 2개의 매개변수를 가짐.
    1. start : 복사를 시작할 인덱스이다. 음수인 경우, 배열의 끝에서의 인덱스를 나타낸다.
      예를 들어 slice(-2)는 배열의 마지막 2개의 요소를 반환한다.
    2. end : 복사를 종료할 인덱스이다. 이 인덱스에 해당하는 요소는 복사되지 않는다. 옵션이며 기본값은 length 값이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const arr = [1, 2, 3];

// arr[0]부터 arr[1] 이전(arr[1] 미포함)까지 복사하여 반환한다.
let result = arr.slice(0, 1);
console.log(result); // [1]

// arr[1]부터 arr[2] 이전(arr[2] 미포함)까지 복사하여 반환한다.
result = arr.slice(1, 2);
console.log(result); // [2]

// 원본은 변경되지 않는다.
console.log(arr); // [1, 2, 3]

// 2번째 인수 생략시 1인수의 인덱스 가 가리킨 곳부터 전부다 복사함.
const result2 = arr.slice(1);
console.log(result2); // [2, 3]

// 인수 전부 생략시 전부 복사해서 새로운 배열 만듬.
const copy = arr.slice();
console.log(copy); // [1, 2, 3]

slice 메소드의 두번째 인수를 생략하면 첫번째 인수에 해당하는 인덱스부터 모든 요소를 복사하여 반환한다.

slice 메소드의 인수를 모두 생략하면 원본 배열의 새로운 복사본을 생성하여 반환한다.

slice는 유사 배열 객체를 배열로 변환시키는 작업에 많이 사용된다.

slice는 얕은 복사를 한다. deep copy는 lodash의 deepClone을 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
function sum() {
// 유사 배열 객체를 배열로 변환
var arr = Array.prototype.slice.call(arguments);
// const arr = [...arguments ]; Spread 문법
console.log(arr); // [1, 2, 3]

return arr.reduce(function (pre, cur) {
return pre + cur;
});
}

console.log(sum(1, 2, 3)); // 6

Array.prototype.indexOf

  • 배열에 인수에 해당되는 요소의 위치(index)를 반환한다.
  • 중복되는 요소가 있는 경우, 첫번째 인덱스를 반환한다.
  • 해당하는 요소가 없는 경우 -1을 반환한다.
  • 두번쨰 인수는 검색을 시작할 인덱스를 지정한다. 생략시 처음부터 검색.
1
2
3
4
5
6
7
8
const arr = [1, 2, 2, 3];

// 배열 arr에서 요소 2를 검색하여 첫번째 인덱스를 반환
arr.indexOf(2); // -> 1
// 배열 arr에서 요소 4가 없으므로 -1을 반환
arr.indexOf(4); // -1
// 두번째 인수는 검색을 시작할 인덱스이다. 두번째 인수를 생략하면 처음부터 검색한다.
arr.indexOf(2, 2); // 2

Array.prototype.join

  • 원본 배열의 모든 요소를 문자열로 변환 후, 구분자로 연결한 문자열을 반환한다.
  • 원본 배열은 유지.
  • 구분자는 생략이 가능하며 기본 구분자는 ; 이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const arr = [1, 2, 3, 4];

// 기본 구분자는 ','이다.
// 원본 배열 arr의 모든 요소를 문자열로 변환한 후, 기본 구분자 ','로 연결한 문자열을 반환
let result = arr.join();
console.log(result); // '1,2,3,4';

// 원본 배열 arr의 모든 요소를 문자열로 변환한 후, 빈문자열로 연결한 문자열을 반환
result = arr.join('');
console.log(result); // '1234'

// 원본 배열 arr의 모든 요소를 문자열로 변환한 후, 구분자 ':'로 연결한 문자열을 반환
result = arr.join(':');
console.log(result); // '1:2:3:4'

Array.prototype.reverse

  • 배열의 요소 순서를 반대로 변경함.
  • 원본 배열 직접 변경.
  • 변경된 배열을 반환한다.
1
2
3
4
5
6
7
const arr = [1, 2, 3];
const result = arr.reverse();

// reverse 메소드는 원본 배열을 직접 변경한다.
console.log(arr); // [3, 2, 1]
// 반환값은 변경된 배열이다.
console.log(result); // [3, 2, 1]

Array.prototype.fill

  • ES6에서 도입됨.
  • 인수로 전달받은 값을 요소로 배열의 처음부터 끝까지 모두 변경함.
  • 원본 배열 직접 변경.
  • 2번째 요소를 생략하면 모든 요소를 다 변경한다.
  • 2번째 요소에 인덱스를 전달하면 해당 인덱스 부터 모든 요소를 다 변경함.
  • 3번쨰 요소에 인덱스를 전달하면 해당 인덱스(자신은 미포함)까지 모든 요소를 다 변경한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const arr = [1, 2, 3];

// 인수로 전달 받은 값 0을 요소로 배열의 처음부터 끝까지 채운다.
arr.fill(0);

// fill 메소드는 원본 배열을 직접 변경한다.
console.log(arr); // [0, 0, 0]

const arr2 = [1, 2, 3];

// 인수로 전달 받은 값 0를 요소로 배열의 인덱스 1부터 끝까지 채운다.
arr2.fill(0, 1);

// fill 메소드는 원본 배열을 직접 변경한다.
console.log(arr2); // [1, 0, 0]

const arr3 = [1, 2, 3, 4, 5];

// 인수로 전달 받은 값 0를 요소로 배열의 인덱스 1부터 3 이전(인덱스 3 미포함)까지 채운다.
arr3.fill(0, 1, 3);

// fill 메소드는 원본 배열을 직접 변경한다.
console.log(arr3); // [1, 0, 0, 4, 5]

fill 메소드는 요소로 채울 경우, 모든 요소를 하나의 값으로만 채울 수 있다.

Array.from을 사용할 경우, 여러개의 값을 만들면서 요소를 채울 수 있다.

1
2
3
4
5
6
// 인수로 전달받은 정수만큼 요소를 생성하고 0부터 1씩 증가하면 요소를 채운다.
function generateSequences(length = 0) {
return Array.from(new Array(length), (v, i) => i);
}

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

Array.prototype.includes

  • ES7에서 새롭게 도입됨.
  • 배열 내에 특정 요소가 포함되어 있는지 확인하여 boolean을 반환.
  • 두번째 인수로 검색을 시작할 인덱스를 전달함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const arr = [1, 2, 3];

// 배열에 요소 2가 포함되어 있는지 확인한다.
let result = arr.includes(2);
console.log(result); // true

// 배열에 요소 100이 포함되어 있는지 확인한다.
result = arr.includes(100);
console.log(result); // false

// 두번째 인수로 검색을 시작할 인덱스를 전달할 수 있다.
// 배열에서 요소 1가 포함되어 있는지 인덱스 1부터 확인한다.
result = arr.includes(1, 1);
console.log(result); // false

배열의 인덱스 위치를 반환하는 Array.prototype.indexOf를 이용해도 배열의 요소가 있는지 없는지 판단이 가능하다.

Array.prototype.indexOf 은 인덱스의 요소가 없을 경우 -1을 반환한다.

하지만 indexOf 메소드는 배열에 NaN이 포함되어 있는지 확인할 수 없는 문제가 있다.

1
2
console.log([NaN].indexOf(NaN) !== -1); // false
console.log([NaN].includes(NaN)); // true

26강 - 2 내용 : 고차 함수


Share