🌕🌑🌑
TL;DR
복습할때나 이 문제가 까먹었을 즈음에 풀어보기
- iterable객체 완성하기
???
구해보기
(2가지 방법으로)1
2
3
4
5
6
7{
[Symbol.iterator](){return this;}
data: [{a:[1,2,3,4], b:'-'}, [5,6,7], 8, 9],
next(){
return ???
}
}
코드스피츠 강의 정리록입니다.
4강 키워드: Generator의 지연실행 측면과 이를 위한 추상루프화
1. abstract loop: 루프의 추상화
1.1 complex recursion 복잡한 반복
단순한 배열 루프인 경우 간단히 이터레이션을 작성할 수 있다.
1 | { |
복잡한 다층형 그래프는 어떻게 이터레이션 할 것인가?
es6와 es6이전의 객체 리터럴의 큰 차이점이 무엇인가
- es6이전
- 기존의 객체 리터럴에서는 객체 리터럴의 순서가 없다.
- 자바로 따지면 hash memory로 되어있다.
- es6
- es6의 객체 리터럴은에서는 객체 리터럴의 순서가 있다.
- linked hash memory로 되어있다.
- 반드시 순서대로 해석된다.
문제
1 | { |
생각해보기 (글쓴이 생각..)
- iterable 프로토콜 유지하기
- 배열 요소들의 타입 검사
- 객체일 경우
객체 내부 키값의 요소들의 타입 검사- 객체일 경우
- 배열일 경우
- 일반 값인 경우
=> 처음 타입 검사와 같은 흐름이므로 해당 flow를 recursive 되도록 한다.
- 어떻게 같은 루프를 다시 태우지..
- 배열일 경우
배열 요소의 타입 검사- 객체일 경우
- 배열일 경우
- 일반 값인 경우
=> 처음 타입 검사와 같은 흐름이므로 해당 flow를 recursive 되도록 한다.
- 어떻게 같은 루프를 다시 태우지..
- 일반 값인 경우
값 반환
cf__1. 루프를 어떻게하면 잘 짤 수 있을까.
루프를 잘 짜고
보다 어려운 로직을 짜는 방법은
내 머리가 선언한 변수만큼을 추적할 수 있어야 한다…
기본적인 알고리즘 전략은 최대한 상태를 덜쓰는것. 내 머리가 추적할 정도로..
정답
각각이 컨테이너 형이라면
그 컨테이너를 다시 해체해서 다시 배열에 붙여준다.
더 이상 컨테이너 형이 아닐 때까지
1 | // 프로토콜만 맞춰주면 된다. |
정답 내의 오류
for(var k in v)
- for…in문은 prototype의 key까지 다 나오기 때문에
hasOwnProperty
를 조건에 추가해야한다.
- hasOwnProperty는 자신의 고유 속성, 즉 상속받은 프로퍼티가 아닌 순수 자신의 속성인 경우에만 true라는 값을 반환하는 특징이 있습니다.
1 | for(var k in v){ |
- 현재 상태에서는 순서 보장이 안된다.
1
2
3let x = [];
for(var k in v) x.push(v[k])
this.data.unshift(...x);
한번더 리팩토링
값인 타입을 v instanceof Object
로 판단할 수 있다!
1 | { |
정리
자바스크립트 언어는 2가지로 되어있다.
- 언어자체의 문법적인 내용,
- 클래스 라이브러리
자바스크립트의 클래스 라이브러리는 코어객체 (Built-in)
Math, Date, RegEx…
=> 표준으로 제공되고 있는 언어 표준의 일부
=> 언어 스팩의 일부
코어객체에 있는 메서드들을 사용하는 것이
기본 언어자체의 문법을 사용하는 것보다 더 안전하다.
ex. for..in보다 Object.values
재사용성 올리기
unshift
나shift
로 인해서 data의 배열이 빈배열이 되는 상황이 된다.
클래스로 묶어서 매번 부를때마다 인스턴스를 반환하는 형태로 만들자.
cf__2. 함수를 변수에 할당하자.
함수를 정의할때 3가지 스타일
- 함수 표현식
- 함수 선언문
- Function…
함수는 값이기 때문에 변수에 할당하는 형식이 맞다. 더 정확하게 호이스팅에 의존하지 않고 어느 시점에 함수를 만들었다를 명확하게 코드로 인지할 수 있기 때문에 function으로 시작하는 함수 정의방법은 아예 금지시키고 못쓰게 하는 경우가 많다. lint에도 함수선언문 금지룰이 있다.
클래스도 하나의 값이다. 변수에 할당이 된다. 변수의 할당 없이 class..로 시작하는 선언방법은 이 클래스가 언제 만들어졌는지 모호하게 만드는 관점이 있다.
1 | const Compx = class { |
shift를 사용하는 것은 data가 배열이 와야하는 조건이 있기 때문에
data의 사본을 만들때 아예 배열화시킨다.const data = [JSON.parse(JSON.stringify(this.data));]
if절을 보면 mandatory가 아닌 optional.
1 | const Compx = class { |
1.2 abstract loop
위의 루프는 목적이 있는 루프이다.
목적이 있는 루프를 만들고 목적을 바꾸면 루프를 다시 짜야한다.
다양한 구조의 루프와 무관하게 해당 값이나 상황의 개입만 하고 싶은 경우
1 | (data, f) => { |
이 상황에서 f(v)를 호출하는 body에 본래 목적과 다른 로직이 추가 될 경우,
같은 로직을 복사하고 원하는 로직을 추가해야하는 상황이 발생한다.
문으로 로직을 작성할 때는 별다른 방법이 없다.
=> 제어문을 재활용할 수 없으므로 중복정의할 수 밖에 없다.
=> 문은 사용하고 나면 재활용할 수 없는데 이걸 어떻게 객체화하지?
결국 제어문을 직접 사용할 수 없고 구조객체를 이용해 루프 실행기를 별도로 구현
구조를 추상화해보자.
- 루프 공통 골격
- 개별구조객체
cf__3. if문을 제거하는 방법
우리가 배우는 거의 모든 priority 기법은 if를 어떻게하면 제거할까에 대한 연구일 수도 있다. 사람은 if가 많아지면 감당이 안된다. 조건이 많아져서..
if를 어떻게하면 제거할 수 있을까?
- 정단한 이유라면 바로 제거할 수 없다. 필요에 의해서 태어났기 때문에
- if로 나눠지는 경우의 수만큼의 값을 미리 만들어 놓고, 바깥쪽에서 그 값을 선택해서 들어오게 하는 수밖에 없다.
아래는 if가 3개이다.
- array일때
- object일때
- primitive일때
3개만큼의 객체를 만들어놓고 바깥쪽에서 객체를 결정하게 끔 만들어 주면 값으로 분리할 수 있게 된다. => 이렇게 if문이 하나씩 제거된다.1
2
3
4
5
6
7
8
9
10
11(data, f) => {
let v;
while(v = data.shift()){
if(!(v instanceof Object)){
f(v)
} else {
if(!Array.isArray(v)) v = Object.values(v);
data.unshift(...v);
}
}
}
팩토리 + 컴포지트
- 선택기는 팩토리 패턴으로
- 각각의 조건문을 컴포지트 패턴으로
cf__4. 팩토리 패턴 참고
- 비슷한 객체를 공장에서 찍어내듯이 반복적으로 생성할 수 있게 하는 패턴
- 컴파일 시점에 구체적인 타입(클래스)을 몰라도 객체 생성이 가능하다
- 팩토리 패턴의 가장 흔한 사례는 Object() 를 이용한 객체 생성시, 주어지는 값의 타입에 따라 String, Boolean, Number 등으로 객체가 생성되는 것이다.
cf__5. composite 패턴
1 | // 😵😵😵 |
- 케이스를 더 많이 늘리는 것도 가능하다..