11. 배열과 객체 좀 더 깊게 살펴보기
ECMAScript2015 + 기능 정리
매개변수 기본값
지정 O
function hello(name, message) {
console.log(`${name}님, ${message}`)
}
hello("도레미", "반갑습니다.") // "도레미님, 반갑습니다."
hello("백두산") // "백두산님, undefined"
지정 X
function hello(name, message = "안녕하세요?") {
console.log(`${name}님, ${message}`)
}
hello("도레미", "반갑습니다.") // "도레미님, 반갑습니다."
hello("백두산") // "백두산님, 안녕하세요?"
전개구문
마침표 세 개(...)의 다양한 쓰임
- 함수
- 매개변수의 개수에 상관없이 매개변수를 하나의 변수로 받을 수 있음
- 배열
- 배열과 배열 연결
- 배열의 값만 꺼내서 복사
// 함수
function addNum(...numbers) {
let sum = 0;
for (let number of numbers)
sum += number;
return sum;
}
console.log(addNum(1, 2)); // 3
console.log(addNum(1, 2, 3, 4, 5)); // 15
// 변수
// 1
let animal = ["bird", "cat"]
let fruits = ["apple", "banana", cherry"]
animal.concat(fruits)
[...animals, ...fruits]
// 2
let fruits = ["apple", "banana", cherry"]
let favorites = fruits
favorite[1] = "grape"
fruits // ["apple", "grape", cherry"]
객체의 프로퍼티
대괄호 표기법
계산된 프로퍼티 이름
프로퍼티 단축
객체에서 심벌키 사용하기
심벌(Symbol)
- ECMAScript2015 이후에 추가된 새로운 원시 자료형
- 한 번 정의하면 값을 변경할 수 없고 유일한 값을 찾음
- 2명 이상의 개발자가 하나의 프로그램 개발: 변수나 프로퍼티 이름을 같게 만드는 실수 피할 수 있음
심벌 사용해 프로퍼티 정의하기
객체 만들면서 일부 정보를 드러내고 싶지 않을 때 심볼 사용
심벌키에 접근하기
- 심벌키를 사용한 프로퍼티나 메서드에 접근 -> 대괄호 사용
- 심벌키를 사용한 메서드를 실행 -> 대괄호의 오른쪽에 소괄호(()) 붙임
const id = Symbol("id)
const tel = Symbol("telephone number")
const member = {
name: "Kime",
age: 25,
[id]: 1235,
[tel]: function() {
alert(prompt("전화번호: "));
}
}
for (item in member) {
console.log(`${item} : ${memeber[item]}`)
}
// name: Kim
// age: 25
member[id] // 1235
member[tel]() // 프롬프트 창에 전화번호 입력 -> 알림 창에 표시
전역 심벌
`Symbol.for()` 메서드
- 키를 인수로 받고 전역 심벌 레지스트리를 뒤져서 키에 해당하는 심벌 찾음
- 레지스트리에 키에 맞는 심벌에 있으면 해당 심벌을 반환, 그렇지 않으면 새로운 심벌은 만들어서 반환
// 기본형
Symbol.for(키)
let tel = Symbol.for("tel") // 처음이므로 심벌 생성
let phone = Symbol.for("tel") // tel 키에 대한 심벌 이미 있으므로 가져와서 사용
tel === phone // true
`Symbol.keyFor()` 메서드
심벌값을 인수로 받아서 전역 심벌 레지스트리를 뒤져서 심벌값의 키를 찾음
// 기본형
Symbol.keyFor(심벌값)
let tel = Symbol.for("tel")
let phone = Symbol.for("tel")
tel === phone
Symbol.keyFor(phone) // "tel"
구조 분해 할당
- 주어진 자료의 구조를 분해해서 변수에 할당하는 기능
- 디스트럭팅(destructing)
- 배열이나 객체는 하나의 변수에 다양한 값 들어 있는데, 그중에서 일부만 꺼내 다른 변수로 할당할 수 있음
// ver1
let [apple, peach] = ["사과", "복숭아"]
// ver2
const fruits = ["사과", "복숭아"]
let [apple, peach] = fruits
일부 값만 분해 할당하기
let [spring, fall, ] = ["봄", "여름", "가을", "겨울"]
spring // "봄"
fall // "가을"
나머지 변수를 사용
- 일부 값을 변수로 지정 -> 나머지 값을 묶어서 하나의 변수로 할당
나머지 변수: 나머지 값을 묶어서 만든 변수 - 나머지 변수 이름 앞에 ...를 붙이고, 나머지 변수에 할당하는 값은 마지막에 오는 값이어야 함
let [teacher, ...students] = ["Kim", "Lee", "Park", "Choi"]
teacher // "Kim"
students // ["Lee", "Park", "Choi"]
두 변수의 값 교환하기
// 일반적인 방법
let tmp;
tmp = x;
x = y;
y = tmp;
// 구조 분해
[x, y] = [y, x]
객체 구조 분해
프로퍼티 이름이나 메서드 이름을 변수 이름으로 사용
-> 객체에는 순서가 없기 때문에 키 이름과 변수 이름이 같아야 해당 키를 찾아서 값을 가져올 수 있음
// 1
const member = {name: "Kim", age: 25}
let {name, age} = member
// 2
let name, age
{name, age} = {name: "Kim", age: 25}
name // "Kim"
age // 25
중첩된 객체 구조 분해
변수의 이름을 객체의 프로퍼티 이름이 아닌 다른 이름으로 지정
cosnt member = {
name: "Kime",
age: 25
}
// name 프로퍼티 값 -> userName 변수에 할당
let {name: userName, age} = member
username // "Kim"
const student = {
name: "도레미",
score: {
history: 85,
science: 84
},
friends: ["Kim", "Lee", "Park"]
}
let {
name, // student.name 값
score: {
history, // studnet.score.history 값
science // student.score.science 값
},
friends: [f1, f2, f3] // friends 배열 구조 분해
} = student
배열을 변형하는 메서드
map() - 배열에 같은 함수 적용
각 배열 요소에 똑같은 함수를 실행한 후 그 결과를 새로운 배열로 반환하는 메서드
// 기본현
map(함수(값))
// ex. numbers 배열의 각 요소에 2를 곱해서 새로운 배열을 만든다면
let numbers = [1, 2, 3, 4, 5]
let newNumbers = numbers.map(number => number * 2);
newNumbers // [2, 4, 6, 8, 10]
// 기본형
map(함수(값, 인덱스))
map(함수(값, 인덱스, 배열))
let numbers = [1, 2, 3, 4, 5]
let newNumbers2 = numbers.map((number, index) => index + (number * 3))
newNumbers2 // [3, 7, 11, 15, 19]
filter() - 특정 조건으로 골라내기
특정 조건에 맞는 요소만 골라내는 메서드
// 기본형
filter(함수(값))
filter(함수(값, 인덱스))
filter(함수(값, 인덱스, 배열))
let scores = [90, 35, 64, 88, 45, 92]
ex. 여러 점수가 저장된 scores 배열에서 85점 이상만 골라서 highScores 배열
highScores = scores.filter(score => score >= 85) // [90, 88, 92]
ex. scores 배열에서 85점 이상의 값 찾으면서 인덱스도
let highScores2 = scores.filter((score, index) => {
if (score >= 85) {
console.log(`index: ${index}, score: ${score}`);
return score;
}
});
reduce() - 값 누적하기
- 배열 요소에 차례로 함수를 실행하면서 결괏값을 하나로 누적하는 메서드
- 초깃값 생략할 수 있음
- 생략 -> 배열의 첫 번째 값을 초깃값으로 사용
// 기본형
reduce(함수(누산기, 현잿값, 인덱스, 원래 배열), 초깃값)
- 현잿값 = 초깃값 + 첫번째 배열 요소 실행한 값
- 현잿값 = 기존 현잿값 + 두번째 배열 요소 실행한 값
- ...
// ex. numbers 배열에 있는 요소를 차례대로 더해서 result에 저장
let numbers = [1, 2, 3, 4, 5]
let result = numbers.reduce((total, current) => total + current, 0);
result // 15
Map과 Set
여러 값을 하나의 변수로 묶어서 처리하기 위해 배열이나 객체 사용
But, 객체로는 부족
- '키'에는 문자열만 사용 X
- 맵에는 키에 모든 값 사용 O
- 여러 정보를 담을 수 있지만, 프로퍼티 간 순서 X
- 맵과 셋에는 순서 O
- for 문과 같은 반복문을 사용해서 객체의 프로퍼티를 반복할 수 X
- 맵과 셋에서는 for...of 같은 반복문 사용 O
- 프로퍼티의 개수를 알려 주는 프로퍼티 X
- 맵과 셋에는 별도의 프로퍼티 O
- 맵과 셋은 배열이나 객체보다 많은 메서드 가지고 있음
맵(Map)
- '키'와 '값'이 하나의 쌍으로 이루어졌고 여러 개의 프로퍼티를 가지고 있는 자료 형태 (객체와 비슷)
- 맵의 프로퍼티키는 문자열뿐만 아니라 모든 자료형을 사용할 수 있음
- 객체나 함수도 사용할 수 있음
맵의 프로퍼티는 순서대로 접근하고 처리할 수 있음
// 기본형
new Map() // Map 객체 만듦
set(키, 값) // Map 객체에 프로퍼티 추가
// ex.
let bag = new Map() // Map
bag.set("color", "red") // {"color" => "red"}
Map 객체를 만들면서 프로퍼티 지정할 수 있음
// 기본형
new Map() ([
[키1, 값1],
[키2, 값2],
...
]);
// ex.
let myCup = new Map ([
["color", "white"],
["haveHandle", true],
["matrial", "ceramic"],
["capacity", "300ml"]
])
myCup
// {"color" => "white", "haveHandle" => true, "material" => "ceramic", "capacity" => "300ml"}
맵 체이닝
bag.set("type", "mini").set("purpose", "daily")
=> 맵의 메서드는 맵을 반환
맵의 프로퍼티와 메서드
// 기본형
size // 맵 요소의 개수 알려주는 프로퍼티
set(키, 값) // 프로퍼티 추가를 추가
get(키) // 해당 키의 값 반환
has(키) // 해당 키가 맵에 있는지 체크하고 true/false 반환
delete(키) // 해당 키가 있는 프로퍼티 삭제
clear() // 맵의 모든 요소 삭제
// 키와 값을 가져오는 메서드
key() // 각 요소의 키를 모아서 반환
values() // 각 요소의 값을 모아서 반환
entries() // [키, 값] 형태로 모든 요소 반환
let myCup = new Map ([
["color", "white"],
["haveHandle", true],
["matrial", "ceramic"],
["capacity", "300ml"]
])
myCup.keys()
// MapIterator {"color", "haveHandle", "material", "capacity"}
for(let key of myCup.keys()) {
console.log(key)
}
- 맵: 순서를 가지고 있는 객체 -> 이터러블 객체
- 키나 값을 가져오는 메서드는 이터러블 객체 반환
셋(Set)
- 배열: 키 없이 여러 개의 값을 모아 놓은 것/ 값이 중복되어도 상관 X
- 셋: 키 없이 여러 개의 값을 모아 놓은 것(= 배열)/ 값 중복 X
Set 객체의 인스턴스 만든 후 값을 추가
// 기본형
new Set()
new Set(배열)
add(값)
// ex.
let numSet1 = new Set()
numSet1.add("one") // {"one"}
numSet1.add("two") // {"one", "two"}
// 체이닝해서 작성
let numSet1 = new Set().add("one").add("two")
배열을 인수로 받아서 셋으로 만들 수 있음
let numSet2 = new Set([1, 2, 3])
numSet2 // {1, 2, 3}
let numSet3 = new Set([1, 2, 1, 3, 1, 5])
numSet3 // {1, 2, 3, 5}
=> 중복 값이 있는 배열을 받아도 중복값을 모두 제거하고 셋을 만듦
셋의 프로퍼티와 메서드
// 기본형
size // 셋 요소의 개수 반환
add(값) // 셋에 값 추가
has(값) // 셋에 해당 값이 있는지 체크
delete(값) // 셋에서 해당 값을 삭제
clear() // 셋을 비움
// 이터러블 객체 반환
keys() // 셋에 있는 모든 값을 반환
values() // 셋에 있는 모든 값을 반환
entries() // [값, 값] 형식으로 모든 값 반환
let students = new Set();
students.add("도레미")
students.add("백두산")
students.add("도레미")
students // {"도레미", "백두산"}
students.key() // {'도레미', '백두산'}
students.values() // {'도레미', '백두산'}
students.entries() // {'도레미' => '도레미', '백두산' => '백두산'}
이터레이터와 제너레이터
이터러블 객체
- 이터러블(iterable): 순서대로 처리할 수 있다
- 문자열, 배열, 맵, 셋
- ex. 배열: 인덱스와 값 -> 인덱스 0부터 차례대로 값을 가져와서 처리할 수 있음
- 기능
- for...of 반복문
- 전개 연산자(...)
- 구조 분해 할당
// ex. 문자열
let hi = "hello";
// for...of
for (let ch of hi) {
console.log(ch)
}
// 전개 연산자
let chArray = [...hi]
chArray // ["h", "e", "l", "l", "o"]
// 구조 분해 할당 사용
let [ch1, ch2] = hi
ch1 // "h"
ch2 // "e"
일반 객체는 이터러블 X
객체 안에 많은 자료를 저장하고 처리해야 함 -> 전개 연산자 or 구조 분해 할당 사용 or for...of문으로 순회하는 것이 편리
=> 일반 객체를 이터러블하게 만들어서 사용(제너레이터 함수 사용)
`Symbol(Symbol.iterator)`: f values()
- 이터러블 객체에는 `Symbol.iterator` 메서드가 포함: 이터러블 프로토콜
- `Symbol.iterator` 메서드 실행 -> `Iterator` 객체 반환
Iterator 객체
- 객체의 요소를 순서대로 꺼낼 수 있는 객체
- `next()` 메서드가 있기 때문에 가능, `value`와 `done` 반환
- `value`: 다음 값
- `done`: 이터레이터 객체가 끝났는지 여부
제너레이터 함수
- 일반 객체를 이터러블하게 만들기 위해 사용하는 함수
- 일반 함수와 구별하기 위해 function 다음에 *기호 붙여서 작성
- 함수 안에 `return` 문 대신에 `yield` 문 사용
// 함수 정의
function* 함수명() {
...
yield
}
// 객체 만들기
객채명 = 함수명()
// ex
function* gen() {
yield 1;
yield 2;
yield 3;
}
// next() 메서드
let g1 = gen()
g1.next() // {value: 1, done: false}
g1.next() // {value: 2, done: false}
g1.next() // {value: 3, done: false}
g1.next() // {value: undefined, done: true}
g1 // gen {<closed>}
// for...of
let g2 = gen()
for (let i of g2) console.log(i)
let g3 = gen()
g3.next() // {value: 1, done: false}
for(let i of g3) console.log(i)
출처
'한국경제신문 with toss bank > FE' 카테고리의 다른 글
[Do it! 모던 자바스크립트 프로그래밍의 정석] 13. 비동기 프로그래밍 (0) | 2024.08.09 |
---|---|
[Do it! 모던 자바스크립트 프로그래밍의 정석] 12. HTTP 통신과 JSON (0) | 2024.08.09 |
[Do it! 모던 자바스크립트 프로그래밍의 정석] 10. 문자열과 배열 (0) | 2024.08.09 |
[Do it! 모던 자바스크립트 프로그래밍의 정석] 07. DOM 활용하기 (0) | 2024.08.09 |
[Do it! 모던 자바스크립트 프로그래밍의 정석] 05. DOM의 기초 (0) | 2024.07.31 |