CH37. Set과 Map
37.1 Set
- Set: 중복되지 않는 유일한 값들의 집합
- 배열과 유사하지만 차이가 있음
- 수학적 집합의 특성과 일치함 (수학적 집합을 구현하기 위한 자료구조)
37.1.1 Set 객체의 생성
- Set 생성자 함수로 생성
- 인수를 전달하지 않으면 빈 Set 객체 생성
- 이터러블을 인수로 전달받아 Set 객체를 생성함
- 이터러블의 중복된 값은 Set 객체에 요소로 저장되지 않음
const set = new Set();
console.log(set); // Set(0) {}
conset set2 = new Set('hello');
console.log(set2); // Set(4) {"h", "e", "l", "o"}
37.1.2 요소 개수 확인
- Set.prototype.size 프로퍼티 사용
- size프로퍼티는 getter 함수만 존재하는 접근자 프로퍼티
: size 프로퍼티에 숫자를 할당해서 Set 객체의 요소 개수를 변경할 수 없음
const {size} = new Set([1, 2, 3, 3]);
console.log(size); // 3
const set = new Set([1, 2, 3]);
console.log(Object.getOwnPropertyDescriptor(Set.prototype, 'size'));
set.size = 10; // 무시 됨
console.log(set.size); // 3
37.1.3 요소 추가
- Set.prototype.add 메서드 사용
- add 메서드를 호출한 후에 add 메서드를 연속적으로 호출할 수 있음
- 중복된 요소의 추가는 허용하지 않음 (에러 발생하지 않고 무시됨)
- 자바스크립의 모든 값을 요소로 저장할 수 있음
const set = new Set();
console.log(set);
set.add(1).add(2).add(2);
console.log(set); // Set(2) {1, 2}
37.1.4 요소 존재 여부 확인
- Set.prototype.has 메서드 사용
const set = new Set([1, 2, 3]);
console.log(set.has(2)); // true
console.log(set.has(4)); // false
37.1.5 요소 삭제
- Set.prototype.delete
- Set 객체에는 순서에 의미가 없으므로, 인덱스가 아니라 삭제하려는 요소 값을 인수로 전달해야 함
- 만약 존재하지 않는 요소를 삭제하려고 하면 에러 없이 무시됨
- 연속적으로 호출 불가
const set = new Set([1, 2, 3]);
set.delete(2);
set.delete(5); // 무시됨
console.log(set); // Set(2) {1, 3}
37.1.6 요소 일괄 삭제
- Set.prototype.clear
- 언제나 undefined 반환
37.1.7 요소 순회
- Set.prototype.forEach
: 첫 번째 인수 - 현재 순회 중인 요소값
: 두 번째 인수 - 현재 순회 중인 요소값
: 세 번째 인수 - 현재 순회 중인 Set 객체 자체
- 첫 번째 인수와 두 번째 인수가 같은 값인 이유는 Array 메서드와 인터페이스를 통일하기 위함
- for ... of 문으로도 순회 가능, 스프레드 문법과 배열 디스트럭처링의 대상이 될 수도 있음
const set = new Set([1, 2, 3]);
set.forEach((v, v2, set) => console.log(v, v2, set));
/*
1 1 Set(3) {1, 2, 3}
2 2 Set(3) {1, 2, 3}
3 3 Set(3) {1, 2, 3}
*/
37.1.8 집합 연산
교집합
Set.prototype.intersection = function (set) {
return new Set([...this].filter(v => set.has(v)));
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);
console.log(setA.intersection(setB)); // Set(2) {2, 4}
합집합
Set.prototype.union = function (set) {
return new Set([...this, ...set]);
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);
console.log(setA.union(setB)); // Set(4) {1, 2, 3, 4}
차집합
Set.prototype.difference = function (set) {
return new Set([...this].filter(v => !set.has(v)));
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);
console.log(setA.difference(setB)); // Set(2) {1, 3}
console.log(setB.difference(setA)); // Set(0) {}
부분 집합과 상위 집합
Set.prototype.isSuperset = function (subset) {
const supersetArr = [...this];
return [...subset].every(v => supersetArr.includes(v));
};
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);
// setA가 setB의 상위 집합인지 확인
console.log(setA.isSuperset(setB)); // true
// 그 반대 확인
console.log(setB.isSuperset(setA)); // false
37.2 Map
- 키와 값의 쌍으로 이루어진 컬렉션
- 객체와 유사하지만 차이가 있음
37.2.1 Map 객체의 생성
- Map 생성자 함수로 생성
- 인수를 전달하지 않으면 빈 Map 객체가 생성됨
- 인수로 전달되는 이터러블은 키와 값의 쌍으로 이루어진 요소로 구성되어야 함
- 중복된 키를 갖는 요소가 존재하면 값이 덮어써짐
const map = new Map();
console.log(map); // Map(0) {}
37.2.2 요소 개수 확인
- Map.prototype.size
- Set과 같은 맥락으로 숫자 할당해서 Map 객체의 요소 개수를 변경할 수 없음
37.2.3 요소 추가
- Map.prototype.set
- 연속적으로 호출 가능
- 중복 값 -> 덮어써짐 / 에러 발생 X
- Map 객체는 키 타입에 제한이 없음
const map = new Map();
map
.set('key1', 'value1')
.set('key1', 'value2');
console.log(map); // Map(1) {'key1' => 'value2'}
37.2.4 요소 취득
- Map.protoptype.get
- get 메서드의 인수로 키를 전달하면 Map 객체에서 인수로 전달한 키를 갖는 값을 반환함
- 존재하지 않는 경우 undefined 반환
const map = new Map();
const lee = {name:'Lee'};
map.set(lee, 'developer');
console.log(map.get(lee)); // developer
37.2.5 요소 존재 여부 확인
- Map.prototype.has
37.2.6 요소 삭제
- Map.prototype.delete
- 존재하지 않는 키 -> 무시/에러 X
- 연속적으로 호출 불가
const map = new Map();
const lee = {name:'Lee'};
map.set(lee, 'developer');
map.delete(lee);
console.log(map)); // Map(0) {}
37.2.7 요소 일괄 삭제
- Map.prototype.clear
- 언제나 undefined 반환
37.2.8 요소 순회
- Map.prototype.forEach
: 첫 번째 인수 - 현재 순회 중인 요소값
: 두 번째 인수 - 현재 순회 중인 요소키
: 세 번째 인수 - 현재 순회 중인 Map 객체 자체
- for ... of 문으로도 순회 가능, 스프레드 문법과 배열 디스트럭처링의 대상이 될 수도 있음
const lee = {name : 'Lee'};
const kim = {name : 'Kim'};
const map = new Map([[lee, 'developer'], [kim, 'desinger']]);
map.forEach((v, k, map) => console.log(v, k, map));
- Map 객체는 이터레이터인 객체를 반환하는 메서드 제공
CH42. 비동기 프로그래밍
42.1 동기 처리와 비동기 처리
- JS 엔진은 단 하나의 실행 컨텍스트 스택을 가짐
: 동시에 2개 이상의 함수를 실행할 수 없음 (싱글 스레드)
- 함수는 호출된 순서대로 스택 자료구조인 실행 컨택스트 스택에 푸시되어 실행
동기 처리
- 다음 예제와 같이 현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식을 동기 처리
- 태스크를 순서대로 하나씩 처리하므로 실행 순서가 보장된다는 장점이 있지만,
앞선 태스크가 종료할 때까지 이후 태스크들이 블로킹된다는 단점
function sleep(func, delay){
const delayUntil = Date.now() + delay;
// 현재 시간에 delay를 더한 delayUntil이 현재 시간보다 작으면 계속 반복
while (Date.now() < delayUntil);
// 일정 시간이 경과한 이후에 콜백 함수를 호출
func();
}
function foo() {
console.log('foo');
}
function bar() {
console.log('bar');
}
// sleep 함수는 3초 이상 실행됨
sleep(foo, 3*1000);
// bar 함수는 sleep 함수의 실행이 종료된 이후에 호출되므로 3초 이상 블로킹 됨
bar();
비동기 처리
fucntion foo() {
console.log('foo');
}
fucntion bar() {
console.log('bar');
}
setTimeout(foo, 3*1000);
bar();
// bar호출하고 3초 경과 후 foo 호출
- 실행 중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식을 비동기 처리
- 현재 실행 중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행 -> 블로킹 발생하지 않음
- 태스크의 실행 순서가 보장되지 않는 단점
- 전통적으로 콜백 패턴을 사용함
: 이 콜백 패턴은 콜백 헬을 발생시켜 가독성을 나쁘게 하고, 비동기 처리 중 발생한 에러의 예외 처리가 곤란
: 여러 개의 비동기 처리를 한 번에 처리하는 데도 한계가 있음
42.2 이벤트 루프와 태스크 큐
이벤트 루프
: 콜 스택에 현재 실행 중인 실행 컨택스트가 있는지, 그리고 태스크 큐에 대기 중인 함수가 있는지 반복해서 확인함
: 만약 콜 스택이 비어있어 태스크 큐에 대기 중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜 스택으로 이동시킴
: 이때 콜 스택으로 이동한 함수는 즉시 실행됨
: 즉, 태스크 큐에 일시 보관된 함수들은 비동기 처리 방식으로 동작함
태스크 큐
: setTimeout이나 setInterval과 같은 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역
: 태스크 큐와는 별도로 프로미스의 후속 처리 메서드의 콜백 함수가 일시적으로 보관되는 마이크로 태스크 큐도 존재함
- JS엔진은 싱글 스레드로 동작하지만, 브라우저는 멀티 스레드로 동작함
'2022-2 웹개발 스터디' 카테고리의 다른 글
[모던 JS] CH41. 타이머, CH43. Ajax (0) | 2022.11.21 |
---|---|
[모던 JS] CH40. 이벤트 (0) | 2022.11.20 |
[모던 JS] CH 34. 이터러블, CH 35. 스프레드 문법, CH 36. 디스트럭처링 할당 # 20 (0) | 2022.11.13 |
[모던 JS] CH 39. DOM (1) | 2022.11.13 |
[모던 JS] CH 38. 브라우저의 렌더링 과정 (0) | 2022.11.12 |