※ 책 [혼자 공부하는 자바스크립트]를 공부하며 기록, 정리해 놓은 노트이다.
배열
요약:
배열 만들기
: 배열의 요소로 어떤 타입이든 다 들어갈 수 있다. (파이썬과 비슷)
> const array = [23, 'Fire!', true, function () {}, {}, [1,2]]
(6) [23, 'Fire!', true, ƒ, {…}, Array(2)]
배열에서 가져오기
> typeof array[3]
'function'
인덱스 자리에 계산식(표현식)을 넣을수도 있다:
> array[2+2]
(2) [1, 2]
배열 길이
> array[array.length-1]
(2) [1, 2]
배열에 추가하기
1. 끝에 추가 - push()
> array.push('하나 더 push!')
7
> array
(7) [23, 'Fire!', true, ƒ, {…}, Array(2), '하나 더 push!']
2. 끝보다 더 뒷자리에 강제 추가 - 인덱스로
> const fruitsA = ['사과']
undefined
> fruitsA[5] = '수박'
'수박'
> fruitsA
(6) ['사과', 비어 있음 × 4, '수박']
0: "사과"
5: "수박"
length: 6
[[Prototype]]: Array(0)
> fruitsA[1]
undefined
3. 중간 위치에 추가하기 - splice()
배열.splice(시작할 인덱스 자리, 0, 추가할 요소들)
splice()의 정확한 사용법은 이렇다:
splice(시작인덱스: number, 제거할개수: number, ...items)
> const berries = ['딸기', '산딸기', '블루베리', '라즈베리', '오미자', '복분자', '오디', '블루베리', '블루베리']
> berries.splice(1, 1, "오디", '오디')
['산딸기']
> berries
(10) ['딸기', '오디', '오디', '블루베리', '라즈베리', '오미자', '복분자', '오디', '블루베리', '블루베리']
배열에서 제거하기
1. 인덱스로 제거하기 - splice()
배열.splice(제거를 시작할 인덱스, 제거할 요소 개수)
// splice = '접합'
> fruitsA.splice(fruitsA.length-1, 3)
['수박']
0: "수박"
length: 1
[[Prototype]]: Array(0)
> fruitsA
(5) ['사과', 비어 있음 × 4]
제거당한 대상은 배열로 반환된다.
‘제거할 요소 개수’가 유효값을 넘어서도 안전하다(아무 일도 없이 있는 것만 잘 제거되고 반환된다).
‘제거를 시작할 인덱스’까지 범위 밖이어도 안전하다(빈 배열을 반환하고 원 배열은 변화가 없다).
중간의 ‘건너 띄어’ 추가된 요소를 지우게 되면 중간의 빈 공간(’건너 띄어진’)도 전부 없어진다. ⇒ 아니다. 아무래도 자바스크립트가 배열을 만드는 방식과 연관이 되어있을 듯. linked list 방식이거나 뭐 그런..?
1-1. 거꾸로 인덱싱(네거티브 인덱싱)이 통한다!
‘제거를 시작할 인덱스’ 자리에만:
> fruitA
(9) ['사과', 비어 있음 × 4, '수박', '산딸기', '블루베리', '멜론']
> fruitA.splice(-2, -2)
[]
> fruitA.splice(-3, 2)
(2) ['산딸기', '블루베리']
> fruitA
(7) ['사과', 비어 있음 × 4, '수박', '멜론']
2. 값으로 제거하기 - indexOf() 후에 splice()
const 타겟인덱스 = 배열.indesOf(요소)
⇒ 배열.splice(타겟인덱스, 1)
> fruitA
(7) ['사과', 비어 있음 × 4, '수박', '멜론']
> fruitA.splice(fruitA.indexOf('수박'))
(2) ['수박', '멜론']
> fruitA
(5) ['사과', 비어 있음 × 4]
indexOf()
는 찾는 요소가 없으면 -1을 반환한다. splice()
가 어떤 숫자를 넣어도 안전하게 반환(유효하지 않은 1번 파라미터나 2번 파라미터라면 빈 배열을 반환하고 아무 제거도 하지 않는다)하므로 둘을 이은 세트 코드는 안전하다.
⇒ 아니다! ‘제거를 시작할 인데스’ 자리에 -1을 넣고 1자리를 지운다고 하면(배열.splice(-1, 1)
) 배열의 마지막 요소를 지우라는 유효한 명령어가 되므로 마지막 요소가 지워지게 된다. 둘을 이은 세트코드가 안전하지 않다.
또한 splice()
의 두번째 인자(’제거할 요소 개수’)를 생략하면 시작 인덱스부터 끝까지를 다 지워버리는 듯.
3. 특정 값을 가진 요소 모두 제거하기 - filter()
> const berries = ['딸기', '산딸기', '블루베리', '라즈베리', '오미자', '복분자', '오디', '블루베리', '블루베리']
> berries.filter((item) => item !== '블루베리')
(6) ['딸기', '산딸기', '라즈베리', '오미자', '복분자', '오디']
> berries
(9) ['딸기', '산딸기', '블루베리', '라즈베리', '오미자', '복분자', '오디', '블루베리', '블루베리']
자료의 비파괴와 파괴
자바스크립트에서 연산자, 함수, 메소드 등을 이용해 자료를 처리할 때, 처리 후 원본의 상태 변화에 따라 처리 방식을 둘로 구분한다.
비파괴적 처리: 처리 후 원본 내용이 변경되지 않음. 안전한 처리. Stable?!
파괴적 처리: 처리 후 원본 내용이 변경됨. Unstable!?
과거에는 메모리를 최대한 적게 차지하게 하기 위해 배열과 같이 거대해질 수 있는 자료를 대부분 파괴적 처리로 다루었다. 그치만 원본이 사라지는 위험이 있기 때문에 메모리가 여유로운 현대에 와서는 자료 보호를 우선시하여 대부분 비파괴적 처리를 하도록 바뀌었다.
따라서 과거에 개발되어 지금까지 표준이 제정되고 개발되고 있는 프로그래밍 언어들을 보면, 초기에 표준화된 것들은 파괴적 처리를 많이 하지만 최근 표준화된 것들은 비파괴적 처리를 많이 하고 있음을 볼 수 있다.
배열 구조 분해 할당
구조 분해 할당이란: ES6
에서 새롭게 도입한 문법으로, 객체(Object) 나 배열(List)을 개별 변수로 ‘분해'할 수 있는 것.
const arr = ["Node.js", "React", "Spring"];
const [backEnd, frontEnd] = arr;
console.log(backEnd); // Node.js
console.log(frontEnd); // React
배열을 분해할 때에는 변수 이름을 마음대로 선언할 수 있고, 배열의 순서대로 할당된다. (객체를 분해할 때엔 속성이나 메소드에 애초에 없는 변수명으로 할당받겠다고 하면 undefined가 할당된다.)
배열 구조 분해 할당으로 선언한 변수를 제외한 나머지 배열의 요소는 할당되지 않는다.
⇒ 한 마디로 배열을 분해할 때 이미 존재하는 요소보다 넘치는 개수에 할당하면 넘친 애들은 ‘undefined’로 정의되고, 모자라는 개수에 할당하면 뒤쪽 애들이 그냥 남게 된다.
구조분해 할당 활용하기
함수의 인자가 객체 또는 배열인 경우 구조 분해 할당을 활용하면 유용하다:
// 구조 분해 할당을 사용하지 않음:
// user가 객체일 때
const getUserName = (user) => {
return user.name
}
// user가 배열일 때
const getUserName = (user) => {
return user[0]
}
// 구조 분해 할당을 사용함:
// 객체일 때
const getUserName = ({name, age}) => {
return name;
};
// 배열일 때
const getUserName = ([name, age]) => {
return name
};
이 노트와 이어진다 : 배열 기반의 다중 할당
⇒ 전개 연산자와 비슷한 면이 있다.
반복문
요약:
for in 반복문
: 배열의 인덱스를 기반으로 반복할 때
더 정확히는, iterable한 객체에 사용되어 요소의 key가 반복 변수로 전달되는 형식이다. 배열에서는 그 key가 인덱스이기 때문에 인덱스 번호가 전달되는 듯하다.
for (const 반복 변수 in 배열 또는 객체) {
...
}
// 예시
const todos = ['일정 확인하기', '이리로 오기', '삼점슛 감상하기', '사심 채우기']
for (const i in todos) {
console.log(`${i}번째 할 일: ${todos[i]}`)
}
=>
0번째 할 일: 일정 확인하기
1번째 할 일: 이리로 오기
2번째 할 일: 삼점슛 감상하기
3번째 할 일: 사심 채우기
- 어떻게 const i를 변수로 책정할 수가 있지? i 값이 계속 바뀌는데다가 상수면 초기화(할당)까지 한번에 마쳐야 하는데…
사실은 이렇게 배열이나 객체의 안정성을 테스트하고(값이 들어있는지를 체크하고?) 사용해야 한다고 한다:
for (const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
}
}
for of 반복문
: 배열의 값을 기반으로 반복할 때
더 정확히는, iterable한 객체의 value를 반복 변수로 하나씩 전달해준다.
for (const 반복 변수 of 배열 또는 객체) {
...
}
// 예시
const todos = ['일정 확인하기', '이리로 오기', '삼점슛 감상하기', '사심 채우기']
for (const todo of todos) {
console.log(`오늘의 할 일: ${todo}`)
}
=>
오늘의 할 일: 일정 확인하기
오늘의 할 일: 이리로 오기
오늘의 할 일: 삼점슛 감상하기
오늘의 할 일: 사심 채우기
for in 반복문과 다르게 인덱스를 사용하지 않기 때문에 안정적이라고 한다.
for 반복문
: 횟수를 기반으로 반복할 때
for (let i = 0; i < 반복 횟수; i++) {
...
}
반복되는 인덱스 자체를 출력하기
1부터 N까지 더하기
배열 출력하기
배열을 반대로 출력하기
여기서는 반드시 ‘변수’ let i
로 지정해주어야 한다. const i
로 할 시 (아마도 i++ 부분 때문에) 상수에 또 할당하려고 하면 발생하는 그 오류(Uncaught TypeError: assignment to constant variable) 발생!
while 반복문
: 조건을 기반으로 반복할 때
while (불 표현식) {
...
}
let i = 0
while (confirm('계속 반복하시겠습니까?')) {
// '확인' 버튼을 누르면 같은 확인창이 계속 뜬다
alert(`${i}번째 반복입니다.`)
i += 1
}
무한 루프(내부에 불 조건을 거짓으로 만들 수 있는 문장이 없는 경우)
자바스크립트에서는 반드시 무한 반복을 벗어나도록 코드를 구현해야 한다. 안 그럼 페이지 전체가 먹통이 되어버리므로. 다른 프로그래밍 언어에서는 ‘데이터를 전달받을 때까지 기다린다’ 같은 목적을 위해 사용하기도 한다는데.
반복문에서 사용할 수 있는 break 와 continue 키워드
break
: switch 조건문이나 반복문을 벗어날 때
continue
: 반복문 안의 현재 위치에서 멈추고 다시 반복문의 처음으로 돌아가 다음 반복작업 하기.
break나 continue 키워드는 반복문의 조건식을 적절하게만 만들면 거의 필요가 없으므로 최대한 덜 사용하도록 해야 한다. 필요없는 구문을 만드는 것을 자제한다는 맥락에서.
중첩 반복문을 사용하는 피라미드 프로그램 1, 2
<script>
// 직각삼각 피라미드 만들기 9층 => N층
/* *
**
***
****
*****
* ... *
*/
let output = ''
let N = 9
for (let i = 1; i <= N; i++) {
let one_line = ''
for (let j = 1; j <= i; j++) {
one_line += '*'
}
output += one_line + '\n'
}
console.log(output)
</script>
<script>
// 이등변삼각 피라미드 만들기 14층 => N층
/*
*
***
*****
*******
* ... *
*** ... ***
*/
let output = ''
let N = 8
for (let i = 1; i <= N; i++) {
// * 개수는 행마다 i*2 - 1개
// 14행에는 27개. 즉 한 줄의 전체 칸 수를 27개로 보고,
// 빈칸 개수는 행마다 왼쪽 13개 오른쪽 13개 -> 하나씩 줄어듬.
// 결국 N층 피라미드의 i번째 행은: (i*2-1)개의 *과
// 양옆에 ((N-i)*2)/2 = N-i개의 빈칸!!
// 왼쪽 빈칸
for (let j = 1; j <= N-i; j++) {
output += ' '
}
// 가운데 별
for (j = 1; j <= i*2-1; j++) {
output += '*'
}
// // 오른쪽 빈칸
// for (j = 1; j <= N-i; j++) {
// output += ' '
// } // 아 오른쪽 빈칸은 굳이 안 해줘도 되겠다.
output += '\n'
}
console.log(output)
// document.body.innerHTML = '<p>' + output + '</p>'
</script>
HTML 지나가는 꿀팁 메소드 하나:
<body> <script> document.body.innerHTML = “<h1>안녕하세요</h1>” </script> <body>
참고:
[책] 혼자 공부하는 자바스크립트 - 윤인성
Uploaded by N2T