-
온보딩 커리큘럼 [배열, 반복문 + 확인문제]항해99(온보딩커리큘럼) 2023. 3. 9. 00:35
배열
let arr = new Array(); let arr = [];
let fruits = ["사과", "오렌지", "자두"]; alert( fruits[0] ); // 사과 alert( fruits[1] ); // 오렌지 alert( fruits[2] ); // 자두
아래는 배열 끝에 무언가를 해주는 메서드입니다.
pop배열 끝 요소를 제거하고, 제거한 요소를 반환합니다.let fruits = ["사과", "오렌지", "배"]; alert( fruits.pop() ); // 배열에서 "배"를 제거하고 제거된 요소를 얼럿창에 띄웁니다. alert( fruits ); // 사과,오렌지
push배열 끝에 요소를 추가합니다.let fruits = ["사과", "오렌지"]; fruits.push("배"); alert( fruits ); // 사과,오렌지,배
아래는 배열 앞에 무언가를 해주는 메서드입니다.shift배열 앞 요소를 제거하고, 제거한 요소를 반환합니다.let fruits = ["사과", "오렌지", "배"]; alert( fruits.shift() ); // 배열에서 "사과"를 제거하고 제거된 요소를 얼럿창에 띄웁니다. alert( fruits ); // 오렌지,배
unshift배열 앞에 요소를 추가합니다.let fruits = ["오렌지", "배"]; fruits.unshift('사과'); alert( fruits ); // 사과,오렌지,배
성능
push와 pop은 빠르지만 shift와 unshift는 느립니다.배열 앞에 무언가를 해주는 메서드가 배열 끝에 무언가를 해주는 메서드보다 느린 이유fruits.shift(); // 배열 맨 앞의 요소를 빼줍니다.
shift 연산은 아래 3가지 동작을 모두 수행해야 이뤄집니다.shift 메서드를 호출한 것과 동일한 효과를 보려면 인덱스가 0인 요소를 제거하는 것만으론 충분하지 않습니다. 제거 대상이 아닌 나머지 요소들의 인덱스를 수정해 줘야 하죠.-
인덱스가 0인 요소를 제거합니다.
-
모든 요소를 왼쪽으로 이동시킵니다. 이때 인덱스 1은 0, 2는 1로 변합니다.
-
length 프로퍼티 값을 갱신합니다.
그런데 배열에 요소가 많으면 요소가 이동하는 데 걸리는 시간이 길고 메모리 관련 연산도 많아집니다.
다차원배열
배열 역시 배열의 요소가 될 수 있습니다. 이런 배열을 가리켜 다차원 배열(multidimensional array)이라 부릅니다. 다차원 배열은 행렬을 저장하는 용도로 쓰입니다.
let matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; alert( matrix[1][1] ); // 5, 중심에 있는 요소
배열과 메서드
splice
splice는 삭제된 요소로 구성된 배열을 반환한다.
만능 스위스 맥가이버 칼 같은 메서드입니다. 요소를 자유자재로 다룰 수 있게 해주죠. 이 메서드를 사용하면 요소 추가, 삭제, 교체가 모두 가능합니다.문법은 다음과 같습니다.arr.splice(index[, deleteCount, elem1, ..., elemN])
요소 삭제let arr = ["I", "study", "JavaScript"]; arr.splice(1, 1); // 인덱스 1부터 요소 한 개를 제거 alert( arr ); // ["I", "JavaScript"]
요소 삭제 후 다른 요소로 교체
let arr = ["I", "study", "JavaScript", "right", "now"]; // 처음(0) 세 개(3)의 요소를 지우고, 이 자리를 다른 요소로 대체합니다. arr.splice(0, 3, "Let's", "dance"); alert( arr ) // now ["Let's", "dance", "right", "now"]
splice 메서드의 deleteCount를 0으로 설정하면 요소를 제거하지 않으면서 새로운 요소를 추가할 수 있습니다
let arr = ["I", "study", "JavaScript"]; // 인덱스 2부터 // 0개의 요소를 삭제합니다. // 그 후, "complex"와 "language"를 추가합니다. arr.splice(2, 0, "complex", "language"); alert( arr ); // "I", "study", "complex", "language", "JavaScript"
음수 인덱스도 사용할 수 있습니다.slice 메서드 뿐만 아니라 배열 관련 메서드엔 음수 인덱스를 사용할 수 있습니다. 이때 마이너스 부호 앞의 숫자는 배열 끝에서부터 센 요소 위치를 나타냅니다.let arr = [1, 2, 5]; // 인덱스 -1부터 (배열 끝에서부터 첫 번째 요소) // 0개의 요소를 삭제하고 // 3과 4를 추가합니다. arr.splice(-1, 0, 3, 4); alert( arr ); // 1,2,3,4,5
slice
arr.slice([start], [end])
이 메서드는 "start" 인덱스부터 ("end"를 제외한) "end"인덱스까지의 요소를 복사한 새로운 배열을 반환합니다. start와 end는 둘 다 음수일 수 있는데 이땐, 배열 끝에서부터의 요소 개수를 의미합니다.arr.slice는 문자열 메서드인 str.slice와 유사하게 동작하는데 arr.slice는 서브 문자열(substring) 대신 서브 배열(subarray)을 반환한다는 점이 다릅니다.let arr = ["t", "e", "s", "t"]; alert( arr.slice(1, 3) ); // e,s (인덱스가 1인 요소부터 인덱스가 3인 요소까지를 복사(인덱스가 3인 요소는 제외)) alert( arr.slice(-2) ); // s,t (인덱스가 -2인 요소부터 제일 끝 요소까지를 복사)
concat
기존 배열의 요소를 사용해 새로운 배열을 만들거나 기존 배열에 요소를 추가하고자 할 때 사용할 수 있습니다.arr.concat(arg1, arg2...)
let arr = [1, 2]; // arr의 요소 모두와 [3,4]의 요소 모두를 한데 모은 새로운 배열이 만들어집니다. alert( arr.concat([3, 4]) ); // 1,2,3,4 // arr의 요소 모두와 [3,4]의 요소 모두, [5,6]의 요소 모두를 모은 새로운 배열이 만들어집니다. alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 // arr의 요소 모두와 [3,4]의 요소 모두, 5와 6을 한데 모은 새로운 배열이 만들어집니다. alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
concat 메서드는 제공받은 배열의 요소를 복사해 활용합니다. 객체가 인자로 넘어오면 (배열처럼 보이는 유사 배열 객체이더라도) 객체는 분해되지 않고 통으로 복사되어 더해집니다
let arr = [1, 2]; let arrayLike = { 0: "something", length: 1 }; alert( arr.concat(arrayLike) ); // 1,2,[object Object]
그런데 인자로 받은 유사 배열 객체에 특수한 프로퍼티 Symbol.isConcatSpreadable이 있으면 concat은 이 객체를 배열처럼 취급합니다. 따라서 객체 전체가 아닌 객체 프로퍼티의 값이 더해집니다.
let arr = [1, 2]; let arrayLike = { 0: "something", 1: "else", [Symbol.isConcatSpreadable]: true, length: 2 }; alert( arr.concat(arrayLike) ); // 1,2,something,else
forEach로 반복 작업 하기.
주어진 함수를 배열 요소 각각에 대해 실행할 수 있게 해줍니다.
arr.forEach(function(item, index, array) { // 요소에 무언가를 할 수 있습니다. });
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { alert(`${item} is at index ${index} in ${array}`); });
인수로 넘겨준 함수의 반환값은 무시됩니다.
배열 탐색하기
indexOf, lastlndexOf, includes
-
arr.indexOf(item, from)는 인덱스 from부터 시작해 item(요소)을 찾습니다. 요소를 발견하면 해당 요소의 인덱스를 반환하고, 발견하지 못했으면 -1을 반환합니다.
-
arr.lastIndexOf(item, from)는 위 메서드와 동일한 기능을 하는데, 검색을 끝에서부터 시작한다는 점만 다릅니다.
-
arr.includes(item, from)는 인덱스 from부터 시작해 item이 있는지를 검색하는데, 해당하는 요소를 발견하면 true를 반환합니다.
let arr = [1, 0, false]; alert( arr.indexOf(0) ); // 1 alert( arr.indexOf(false) ); // 2 alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true
위 메서드들은 요소를 찾을 때 완전 항등 연산자 === 을 사용한다는 점에 유의하시기 바랍니다. 보시는 바와 같이 false를 검색하면 정확히 false만을 검색하지, 0을 검색하진 않습니다.
const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (완전 항등 비교 === 는 NaN엔 동작하지 않으므로 0이 출력되지 않습니다.) alert( arr.includes(NaN) );// true (NaN의 여부를 확인하였습니다.)
find와 findIndex
특정조건에 부합하는 객체를 배열에서 찾을 수 있다.
find 메서드는 함수의 반환 값을 true로 만드는 단 하나의 요소를 찾습니다.
let result = arr.find(function(item, index, array) { // true가 반환되면 반복이 멈추고 해당 요소를 반환합니다. // 조건에 해당하는 요소가 없으면 undefined를 반환합니다. });
요소 전체를 대상으로 함수가 순차적으로 호출됩니다.
-
item – 함수를 호출할 요소
-
index – 요소의 인덱스
-
array – 배열 자기 자신
함수가 참을 반환하면 탐색은 중단되고 해당 요소가 반환됩니다. 원하는 요소를 찾지 못했으면 undefined가 반환됩니다.
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이 반환됩니다.filter
filter는 find와 문법이 유사하지만, 조건에 맞는 요소 전체를 담은 배열을 반환한다는 점에서 차이가 있습니다.
let results = arr.filter(function(item, index, array) { // 조건을 충족하는 요소는 results에 순차적으로 더해집니다. // 조건을 충족하는 요소가 하나도 없으면 빈 배열이 반환됩니다. });
let users = [ {id: 1, name: "John"}, {id: 2, name: "Pete"}, {id: 3, name: "Mary"} ]; // 앞쪽 사용자 두 명을 반환합니다. let someUsers = users.filter(item => item.id < 3); alert(someUsers.length); // 2
배열을 변형하는 메서드
map
map은 배열 요소 전체를 대상으로 함수를 호출하고, 함수 호출 결과를 배열로 반환해줍니다.
let result = arr.map(function(item, index, array) { // 요소 대신 새로운 값을 반환합니다. });
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length); alert(lengths); // 5,7,6
sort(fn)
배열의 요소를 정렬해줍니다. 배열 자체가 변경됩니다.
메서드를 호출하면 재정렬 된 배열이 반환되는데, 이미 arr 자체가 수정되었기 때문에 반환 값은 잘 사용되지 않는 편입니다.
요소는 문자열로 취급되어 사전순으로 재 정렬된다.
숫자를 정렬하려면 기본 정렬 기준 대신 새로운 정렬 기준을 만들려면 arr.sort()에 새로운 함수를 넘겨줘야 합니다.
function compareNumeric(a, b) { if (a > b) return 1; if (a == b) return 0; if (a < b) return -1; } let arr = [ 1, 2, 15 ]; arr.sort(compareNumeric); alert(arr); // 1, 2, 15
화살표 함수를 이용한 정렬 함수
arr.sort( (a, b) => a - b );
reverse
arr의 요소를 역순으로 정렬시켜주는 메서드입니다.
let arr = [1, 2, 3, 4, 5]; arr.reverse(); alert( arr ); // 5,4,3,2,1
split과 join
이 메서드는 구분자(delimiter) delim을 기준으로 문자열을 쪼개줍니다.
let names = 'Bilbo, Gandalf, Nazgul'; let arr = names.split(', '); for (let name of arr) { alert( `${name}에게 보내는 메시지` ); // Bilbo에게 보내는 메시지 }
split 메서드는 두 번째 인수로 숫자를 받을 수 있습니다. 이 숫자는 배열의 길이를 제한해주므로 길이를 넘어서는 요소를 무시할 수 있습니다. 실무에서 자주 사용하는 기능은 아닙니다.
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2); alert(arr); // Bilbo, Gandalf
split(s)의 s를 빈 문자열로 지정하면 문자열을 글자 단위로 분리할 수 있습니다.
let str = "test"; alert( str.split('') ); // t,e,s,t
arr.join은 split과 반대 역할을 하는 메서드입니다. 인수 glue를 접착제처럼 사용해 배열 요소를 모두 합친 후 하나의 문자열을 만들어줍니다.
let arr = ['Bilbo', 'Gandalf', 'Nazgul']; let str = arr.join(';'); // 배열 요소 모두를 ;를 사용해 하나의 문자열로 합칩니다. alert( str ); // Bilbo;Gandalf;Nazgul
reduce와 reduceRight
reduce와 reduceRight는 배열을 기반으로 값 하나를 도출할 때 사용됩니다.
let value = arr.reduce(function(accumulator, item, index, array) { // ... }, [initial]);
-
accumulator – 이전 함수 호출의 결과. initial은 함수 최초 호출 시 사용되는 초깃값을 나타냄(옵션)
-
item – 현재 배열 요소
-
index – 요소의 위치
-
array – 배열
이전 함수 호출 결과는 다음 함수를 호출할 때 첫 번째 인수(previousValue)로 사용됩니다.
첫 번째 인수는 앞서 호출했던 함수들의 결과가 누적되어 저장되는 '누산기(accumulator)'라고 생각하면 됩니다. 마지막 함수까지 호출되면 이 값은 reduce의 반환 값이 됩니다
let arr = [1, 2, 3, 4, 5]; let result = arr.reduce((sum, current) => sum + current, 0); alert(result); // 15
-
함수 최초 호출 시, reduce의 마지막 인수인 0(초깃값)이 sum에 할당됩니다. current엔 배열의 첫 번째 요소인 1이 할당됩니다. 따라서 함수의 결과는 1이 됩니다.
-
두 번째 호출 시, sum = 1 이고 여기에 배열의 두 번째 요소(2)가 더해지므로 결과는 3이 됩니다.
-
세 번째 호출 시, sum = 3 이고 여기에 배열의 다음 요소가 더해집니다. 이런 과정이 계속 이어집니다.
Array.isArray로 배열 여부 알아내기
자바스크립트에서 배열은 독립된 자료형으로 취급되지 않고 객체형에 속합니다.따라서 typeof로는 일반 객체와 배열을 구분할 수가 없죠.alert(typeof {}); // object alert(typeof []); // object
그런데 배열은 자주 사용되는 자료구조이기 때문에 배열인지 아닌지를 감별해내는 특별한 메서드가 있다면 아주 유용할 겁니다. Array.isArray(value)는 이럴 때 사용할 수 있는 유용한 메서드입니다. value가 배열이라면 true를, 배열이 아니라면 false를 반환해주죠.
alert(Array.isArray({})); // false alert(Array.isArray([])); // true
배열 메서드와 'thisArg'
함수를 호출하는 대부분의 배열 메서드(find, filter, map 등. sort는 제외)는 thisArg라는 매개변수를 옵션으로 받을 수 있습니다
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
thisArgs에 army를 지정하지 않고 단순히 users.filter(army.canJoin)를 사용했다면 army.canJoin은 단독 함수처럼 취급되고, 함수 본문 내 this는 undefined가 되어 에러가 발생했을 겁니다.users.filter(user => army.canJoin(user))를 사용하면 users.filter(army.canJoin, army)를 대체할 수 있긴 한데 thisArg를 사용하는 방식이 좀 더 이해하기 쉬우므로 더 자주 사용됩니다.<배열 확인문제>
- 다음 배열들의 2번째 인덱스에 있는 값을 찾아보세요.
- [”1”, ”2”, ”3”, ”4”] → “3”
- [”사과”, “배”, “바나나”, “귤”, “감”] →”바나나”
- [52, 273, 32, 103, 57] → 32
- 다음 코드의 실행 결과를 예측해보세요.
const array = [1, 2, 3, 4] console.log(array.length) console.log(array.push(5)) // 4 // 5
3. 다음 표시된 함수들이 파괴적 처리를 하는지 비파괴적 처리를 하는지 구분해 맞는것에 O 표시하세요.
[파괴적 처리 / 비파괴적 처리]
const strA = "사과,배,바나나,귤" //undefined strA.split(",") //(4)["사과","배","바나나","귤"] strA //"사과,배,바나나,귤"
[파괴적 처리 / 비파괴적 처리]
const arrayB = ["사과", "배", "바나나", "귤"] // undefined arrayB.push("감") // 5 arrayB // ["사과", "배", "바나나", "귤", "감"]
[파괴적 처리 / 비파괴적 처리]
const arrayC = [1,2,3,4,5] // undefined arrayC.map((x) => x*x) // (5) [1,4,9,16,25] arrayC // (5)[1,2,3,4,5]
[파괴적 처리 / 비파괴적 처리]
const strD = " 여백이 포함된 메세지 " // undefined strD.trim() // "여백이 포함된 메세지" strD // " 여백이 포함된 메세지 "
<반복문 확인문제>
1. 다음 프로그램의 실행 결과를 예측해보세요.
const array = ['사과', '배', '귤', '바나나'] console.log('# for in 반복문') //index를 반환한다. for (const i in array) { console.log(i) } // # for in 반복문 // 0 // 1 // 2 // 3 console.log('# for of 반복문')//요소를 반환한다. for (const i of array) { console.log(i) } // # for of 반복문 // 사과 // 배 // 귤 // 바나나
2. 다음 프로그램의 실행 결과를 예측해보세요. 혹시 오류가 발생한다면 어디를 수정해야 할까요?
const array = [] for (const i = 0; i < 3; i++) { array.push((i + 1) * 3) } console.log(array) // const는 상수이기 떄문에 i++가 되었을때 오류가 발생한다. let으로 변경하면 // [3, 6, 9] 가 출력된다.
3. 1부터 100까지의 숫자를 곱한 값을 계산하는 프로그램을 만들어보세요. 그리고 코드를 실행해 나온 결과를 확인해 보세요.
let output = 1 for (i = 1; i <= 100; i++) { output *= i } console.log(`1~100의 숫자를 모두 곱하면 ${output}입니다.`) //1~100의 숫자를 모두 곱하면 9.33262154439441e+157입니다.
4. 처음에는 조금 어려울 수 있겠지만, 활용 예제의 피라미드를 활용해서 다음과 같은 피라미드를 만들어보세요.
* *** ***** ******* ***** *** * let output = '' const size = 5 for (let i = 1; i < 5; i++) { for (let j = 5; j > i; j--) { output += ' ' } for (let k = 1; k < i * 2; k++) { output += '*' } output += '\n' } for (let i = size - 1; i > 0; i--) { for (let j = 6; j > i + 1; j--) { output += ' ' } for (let k = 0; k < 2 * i - 1; k++) { output += '*' } output += '\n' } console.log(output)
'항해99(온보딩커리큘럼)' 카테고리의 다른 글
온보딩 커리큘럼[함수의 기본 형태] (1) 2023.03.10 온보딩 커리큘럼 [배열, 반복문(2)] (0) 2023.03.09 온보딩 커리큘럼 [조건문(if, switch)] (0) 2023.03.07 온보딩 커리큘럼 [js기본 문법] (0) 2023.03.07 항해99 사전스터디 [2회차] (2) 2023.02.16 -