배열은 특수한 형태의 객체로, 순서가 있는 자료를 저장하고 관리하는 용도에 최적화된 자료구조입니다.
- 선언 방법:
// 대괄호 (가장 많이 쓰이는 방법임) let arr = [item1, item2...]; // new Array (잘 쓰이지 않음) let arr = new Array(item1, item2...);
new Array(number)
을 호출하면 길이가number
인 배열이 만들어지는데, 이 때 요소는 비어있습니다.
length
프로퍼티는 배열의 길이를 나타내줍니다. 정확히는 숫자형 인덱스 중 가장 큰 값에 1을 더한 값입니다. 배열 메서드는 length 프로퍼티를 자동으로 조정해줍니다.length
값을 수동으로 줄이면 배열 끝이 잘립니다.(되돌릴 수 없음)다음 연산을 사용하면 배열을 데큐처럼 사용할 수 있습니다.
push(...items)
– items를 배열 끝에 더해줍니다.pop()
– 배열 끝 요소를 제거하고, 제거한 요소를 반환합니다.shift()
– 배열 처음 요소를 제거하고, 제거한 요소를 반환합니다.unshift(...items)
– items를 배열 처음에 더해줍니다.아래 방법을 사용하면 모든 요소를 대상으로 반복 작업을 할 수 있습니다.
for (let i=0; i<arr.length; i++)
– 가장 빠른 방법이고 오래된 브라우저와도 호환됩니다.for (let item of arr)
– 배열 요소에만 사용되는 모던한 문법입니다.(인덱스를 모름)for (let i in arr)
– 배열엔 절대 사용하지 마세요.
배열
사용 가능let arr = new Array();
let arr = [];
let fruits = ["사과", "오렌지", "자두"];
let fruits = ["사과", "오렌지", "자두"];
alert( fruits[0] ); // 사과
alert( fruits[1] ); // 오렌지
alert( fruits[2] ); // 자두
let fruits = ["사과", "오렌지", "자두"];
alert( fruits.length ); // 3
push
– 맨 끝에 요소를 추가shift
– 제일 앞 요소를 꺼내 제거한 후 남아있는 요소들을 앞으로 밀어주어 두 번째 요소가 첫 번째 요소가 됨push
– 요소를 스택 끝에 집어넣음pop
– 스택 끝 요소를 추출pop
: 배열 끝 요소를 제거하고, 제거한 요소를 반환push
: 배열 끝에 요소를 추가shift
: 배열 앞 요소를 제거하고, 제거한 요소를 반환unshift
: 배열 앞에 요소를 추가push
와 unshift
는 요소 여러 개를 한 번에 더해줄 수도 있음push
와 pop
은 빠르지만 shift
와 unshift
는 느림shift
나 unshift
가 느린 이유는 추가하거나 제거한 요소 이외의 모든 요소를 이동시켜야하기 때문(index
재배정)for
let arr = ["사과", "오렌지", "배"];
for (let i = 0; i < arr.length; i++) {
alert( arr[i] );
}
for...of
let fruits = ["사과", "오렌지", "자두"];
// 배열 요소를 대상으로 반복 작업을 수행
for (let fruit of fruits) {
alert( fruit );
}
for...in
(🚨 배열에 사용을 지양)for...in
사용을 지양index
가 0부터 시작하기 때문)arr.length = 0;
let arr = new Array("사과", "배", "기타");
new Array
를 호출하면 배열이 만들어지는데, 이 배열엔 요소가 없는 반면 길이는 인수와 같아짐new Array(number)
를 이용해 만든 배열의 요소는 모두 undefined
요약
요소를 더하거나 지우기
- push(...items) – 맨 끝에 요소 추가하기
- pop() – 맨 끝 요소 추출하기
- shift() – 첫 요소 추출하기
- unshift(...items) – 맨 앞에 요소 추가하기
- splice(pos, deleteCount, ...items) – pos부터 deleteCount개의 요소를 지우고, items 추가하기
- slice(start, end) – start부터 end 바로 앞까지의 요소를 복사해 새로운 배열을 만듦
- concat(...items) – 배열의 모든 요소를 복사하고 items를 추가해 새로운 배열을 만든 후 이를 반환함. items가 배열이면 이 배열의 인수를 기존 배열에 더해줌
원하는 요소 찾기
- indexOf/lastIndexOf(item, pos) – pos부터 원하는 item을 찾음. 찾게 되면 해당 요소의 인덱스를, 아니면 -1을 반환함
- includes(value) – 배열에 value가 있으면 true를, 그렇지 않으면 false를 반환함
- find/filter(func) – func의 반환 값을 true로 만드는 첫 번째/전체 요소를 반환함
- findIndex는 find와 유사함. 다만 요소 대신 인덱스를 반환함
배열 전체 순회하기
- forEach(func) – 모든 요소에 func을 호출함. 결과는 반환되지 않음
배열 변형하기
- map(func) – 모든 요소에 func을 호출하고, 반환된 결과를 가지고 새로운 배열을 만듦
- sort(func) – 배열을 정렬하고 정렬된 배열을 반환함
- reverse() – 배열을 뒤집어 반환함
- split/join – 문자열을 배열로, 배열을 문자열로 변환함
reduce(func, initial) – 요소를 차례로 돌면서 func을 호출함. 반환값은 다음 함수 호출에 전달함. 최종적으로 하나의 값이 도출됨기타
- Array.isArray(arr) – arr이 배열인지 여부를 판단함
- some(fn) - 모든 요소를 대상으로 함수를 호출하고 함수의 반환 값을 true로 만드는 요소가 하나라도 있는지 여부를 확인
- every(fn) - 모든 요소를 대상으로 함수를 호출하고 함수의 반환 값을 true로 만드는지 여부를 확인
- fill(value, start, end)은 start부터 end까지 value를 채워 넣습니다.
- copyWithin(target, start, end)은 start부터 end까지 요소를 복사하고, 복사한 요소를 target에 붙여넣습니다. 기존 요소가 있다면 덮어씁니다.
🚨 sort, reverse, splice는 기존 배열을 변형시킨다는 점에 주의하시기 바랍니다.
arr.splice(index[, deleteCount, elem1, ..., elemN])
arr.splice(1, 1);
arr.splice(0, 3, "Let's", "dance");
splice
메서드의 deleteCount
를 0
으로 설정하면 요소를 제거하지 않으면서 새로운 요소를 추가 가능
delete
연산자
delete obj.key
는key
를 이용해 해당 키에 상응하는 값을 지우기 때문에 삭제된 요소가 만든 빈 공간을 나머지 요소들이 자동으로 채우지 않음- 즉, 배열의 길이는 그대로임
arr.slice([start], [end])
start
인덱스부터 (end
를 제외한) end
인덱스까지의 요소를 복사한 새로운 배열을 반환start
와 end
는 둘 다 음수일 수 있는데 이땐, 배열 끝에서부터의 요소 개수를 의미함배열 복사
arr.slice()
는 인수를 하나도 넘기지 않고 호출하여 arr의 복사본을 만들 수 있음
arr.concat
은 기존 배열의 요소를 사용해 새로운 배열을 만들거나 기존 배열에 요소를 추가하고자 할 때 사용arr.concat(arg1, arg2...)
let arr = [1, 2];
let arrayLike = {
0: "something",
length: 1
};
alert( arr.concat(arrayLike) ); // 1,2,[object Object]
arr.forEach
는 주어진 함수를 배열 요소 각각에 대해 실행할 수 있게 해줌arr.forEach(function(item, index, array) {
// 요소에 무언가를 할 수 있습니다.
});
arr.indexOf(item, from)
는 인덱스 from
부터 시작해 item(요소)
을 찾는데, 요소를 발견하면 해당 요소의 인덱스를 반환하고, 발견하지 못했으면 -1
을 반환함arr.lastIndexOf(item, from)
는 위 메서드와 동일한 기능을 하는데, 검색을 끝에서부터 시작한다는 점만 다름arr.includes(item, from)
는 인덱스 from
부터 시작해 item
이 있는지를 검색하는데, 해당하는 요소를 발견하면 true
를 반환함===
을 사용한다는 점에 유의(false
를 검색하면 정확히 false
만을 검색하지, 0을 검색하진 않음)includes
는 NaN
도 제대로 처리할 수 있음arr.find(fn)
: 객체로 이루어진 배열에서 특정 조건에 부합하는 객체를 배열 내에서 찾음let result = arr.find(function(item, index, array) {
// true가 반환되면 반복이 멈추고 해당 요소를 반환
// 조건에 해당하는 요소가 없으면 undefined를 반환
});
id==1
조건을 충족하는 객체 find
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let user = users.find(item => item.id == 1);
alert(user.name); // John
arr.findIndex
는 find
와 동일한 일을 하나, 조건에 맞는 요소를 반환하는 대신 해당 요소의 인덱스를 반환(조건에 맞는 요소가 없으면 -1
이 반환)find
와 달리 조건을 충족하는 요소가 여러 개라면 arr.filter(fn)
를 사용filter
는 find
와 문법이 유사하지만, 조건에 맞는 요소 전체를 담은 배열을 반환함let results = arr.filter(function(item, index, array) {
// 조건을 충족하는 요소는 results에 순차적으로 더해짐
// 조건을 충족하는 요소가 하나도 없으면 빈 배열을 반환
});
arr.map
은 유용성과 사용 빈도가 아주 높은 메서드map
은 배열 요소 전체를 대상으로 함수를 호출하고, 함수 호출 결과를 배열로 반환해줌let result = arr.map(function(item, index, array) {
// 요소 대신 새로운 값을 반환
// 기존 arr 배열에는 변화가 없음
});
let arr = [ 1, 2, 15 ];
arr.sort(); // arr 내부가 재정렬됨
alert( arr ); // 1, 15, 2
let arr = [ 1, 2, 15 ];
function compare(a, b) {
if (a > b) return 1; // 첫 번째 값이 두 번째 값보다 큰 경우
if (a == b) return 0; // 두 값이 같은 경우
if (a < b) return -1; // 첫 번째 값이 두 번째 값보다 작은 경우
}
arr.sort(compare);
// 리팩토링(1)
arr.sort(function(a, b) { return a - b; });
// 리팩토링(2)
arr.sort( (a, b) => a - b );
arr.reverse
는 arr
의 요소를 역순으로 정렬시켜줌let arr = [1, 2, 3, 4, 5];
arr.reverse();
alert( arr ); // 5,4,3,2,1
str.split(delim)
을 이용하면 구분자(delimiter) delim
을 기준으로 문자열을 쪼개줌let names = 'Bilbo, Gandalf, Nazgul';
let arr = names.split(', ');
console.log(arr) // ["Bilbo", "Gandalf", "Nazgul"]
split
메서드는 두 번째 인수로 숫잗를 받아서 배열의 길이를 제한해줄 수 있음문자열을 글자 단위로 분리하기
split(s)
의s
를 빈 문자열로 지정하면 문자열을 글자 단위로 분리 가능let str = "test"; alert( str.split('') ); // t,e,s,t
join
arr.join(glue)
은split
과 반대 역할을 하는 메서드- 인수
glue
를 접착제처럼 사용해 배열 요소를 모두 합친 후 하나의 문자열을 만들어줌let arr = ['Bilbo', 'Gandalf', 'Nazgul']; let str = arr.join(';'); // 배열 요소 모두를 ;를 사용해 하나의 문자열로 합침 alert( str ); // Bilbo;Gandalf;Nazgul
let value = arr.reduce(function(acc, cur, index, array) {
// ...
}, [initial]);
acc
– accumulator, 이전 함수 호출의 결과. initial
은 함수 최초 호출 시 사용되는 초깃값을 나타냄(옵션)cur
– current, 현재 배열 요소index
– 요소의 위치array
– 배열let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert(result); // 15
reduce
를 사용할 시, 배열이 비어있는 상태면 reduce 호출 시 에러가 발생할 수 있음arr.reduceRight
는 reduce
와 동일한 기능을 하지만 배열의 오른쪽부터 연산을 수행한다는 점이 다름typeof
로는 일반 객체와 배열을 구분할 수가 없음Array.isArray(value)
는 value
가 배열이라면 true
를, 배열이 아니라면 false
를 반환alert(typeof {}); // object
alert(typeof []); // object
alert(Array.isArray({})); // false
alert(Array.isArray([])); // true
find
, filter
, map
등)는 thisArg
라는 매개변수를 옵션으로 받을 수 있음(sort
는 제외)thisArg
는 func
의 this
arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
// thisArg는 선택적으로 사용할 수 있는 마지막 인수입니다.
let army = {
minAge: 18,
maxAge: 27,
canJoin(user) {
return user.age >= this.minAge && user.age < this.maxAge;
}
};
let users = [
{age: 16},
{age: 20},
{age: 23},
{age: 30}
];
// army.canJoin 호출 시 참을 반환해주는 user를 찾음
let soldiers = users.filter(army.canJoin, army);
alert(soldiers.length); // 2
alert(soldiers[0].age); // 20
alert(soldiers[1].age); // 23
요약
for..of
을 사용할 수 있는 객체를 이터러블이라고 부릅니다.
- 이터러블엔 메서드Symbol.iterator
가 반드시 구현되어 있어야 합니다.
-obj[Symbol.iterator]
의 결과는 이터레이터라고 부릅니다. 이터레이터는 이어지는 반복 과정을 처리합니다.
- 이터레이터엔 객체{done: Boolean, value: any}
을 반환하는 메서드next()
가 반드시 구현되어 있어야 합니다. 여기서done:true
은 반복이 끝났음을 의미하고 그렇지 않은 경우엔value
가 다음 값이 됩니다.- 메서드
Symbol.iterator
는for..of
에 의해 자동으로 호출되는데, 개발자가 명시적으로 호출하는 것도 가능합니다.- 문자열이나 배열 같은 내장 이터러블에도
Symbol.iterator
가 구현되어 있습니다.- 문자열 이터레이터는 서로게이트 쌍을 지원합니다.
인덱스와 length 프로퍼티가 있는 객체는 유사 배열이라 불립니다. 유사 배열 객체엔 다양한 프로퍼티와 메서드가 있을 수 있는데 배열 내장 메서드는 없습니다.
명세서를 보면 대부분의 메서드는 ‘진짜’ 배열이 아닌 이터러블이나 유사 배열을 대상으로 동작한다고 쓰여 있는걸 볼 수 있습니다. 이 방법이 더 추상적이기 때문입니다.
Array.from(obj[, mapFn, thisArg])을 사용하면 이터러블이나 유사 배열인 obj를 진짜 Array로 만들 수 있습니다. 이렇게 하면 obj에도 배열 메서드를 사용할 수 있죠. 선택 인수 mapFn와 thisArg는 각 요소에 함수를 적용할 수 있게 해줍니다.
for..of
문법을 적용할 수만 있다면 컬렉션을 순회하는데 유용할 것임let range = {
from: 1,
to: 5
};
// 아래와 같이 for..of가 동작할 수 있도록 하는 게 목표임
// for(let num of range) ... num=1,2,3,4,5
range
를 이터러블로 만들려면(for..of
가 동작하도록 하려면) 객체에 Symbol.iterator
(특수 내장 심볼)라는 메서드를 추가해 아래와 같은 일이 벌어지도록 해야함for..of
가 시작되자마자 for..of
는 Symbol.iterator
를 호출합니다.Symbol.iterator
가 없으면 에러가 발생합니다)Symbol.iterator
는 반드시 이터레이터(iterator
, 메서드 next
가 있는 객체) 를 반환해야 합니다.for..of
는 반환된 객체(이터레이터)만을 대상으로 동작합니다.for..of
에 다음 값이 필요하면, for..of
는 이터레이터의 next()
메서드를 호출합니다.next()
의 반환 값은 {done: Boolean, value: any}
와 같은 형태이어야 합니다. done=true
는 반복이 종료되었음을 의미합니다. done=false
일땐 value
에 다음 값이 저장됩니다.let range = {
from: 1,
to: 5
};
// 1. for..of 최초 호출 시, Symbol.iterator가 호출됩니다.
range[Symbol.iterator] = function() {
// Symbol.iterator는 이터레이터 객체를 반환합니다.
// 2. 이후 for..of는 반환된 이터레이터 객체만을 대상으로 동작하는데, 이때 다음 값도 정해집니다.
return {
current: this.from,
last: this.to,
// 3. for..of 반복문에 의해 반복마다 next()가 호출됩니다.
next() {
// 4. next()는 값을 객체 {done:.., value :...}형태로 반환해야 합니다.
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// 이제 의도한 대로 동작합니다!
for (let num of range) {
alert(num); // 1, then 2, 3, 4, 5
}
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
this.current = this.from;
return this;
},
next() {
if (this.current <= this.to) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
for (let num of range) {
alert(num); // 1, then 2, 3, 4, 5
}
for..of
는 문자열의 각 글자를 순회함for (let char of "test") {
// 글자 하나당 한 번 실행됩니다(4회 호출).
alert( char ); // t, e, s, t가 차례대로 출력됨
}
let str = "Hello";
// for..of를 사용한 것과 동일한 작업을 합니다.
// for (let char of str) alert(char);
let iterator = str[Symbol.iterator]();
while (true) {
let result = iterator.next();
if (result.done) break;
alert(result.value); // 글자가 하나씩 출력됩니다.
}
let arrayLike = {
0: "Hello",
1: "World",
length: 2
};
let arr = Array.from(arrayLike); // (*)
alert(arr.pop()); // World (메서드가 제대로 동작합니다.)
Array.from(obj[, mapFn, thisArg])
mapFn
을 두 번째 인수로 넘겨주면 새로운 배열에 obj
의 요소를 추가하기 전에 각 요소를 대상으로 mapFn
을 적용할 수 있음thisArg
는 각 요소의 this
를 지정할 수 있도록 해줌