# Step05
# Iterator
Iterator 과 Iterable 의 구분에 대해 더 잘 알필요가 있다고 생각합니다.
# by 정웅
- NodeLists 도 iterable 이다.
const nodeLists = document.querySelectorAll('*');
[...nodeLists];
for (const v of nodeLists) {
console.log(v)
}
2
3
4
5
6
7
- 생성자 함수는 yield 키워드를 만날때 까지 실행된다.
Generator 는 next 메소드를 통해 호출되면 어떤 값이 소비되고 생성자 함수는 yield 키워드를 만날때 까지 실행된다.
# to 정웅
Q. 'value 값과 done 값이 모두 참이 되면' 문구가 애매 한 것 같습니다. value 가 참인 것을 어떻게 무슨기준으로 확인할까요?
Iterator 란 Arrays, Strings, Maps, Sets, NodeLists 에 포함된 built-in Object 이다.
Iterator 는 두 개의 속성 (value, done) 을 반환하는 next() 메소드를 사용하여 객체의 Iterator protocol 을 구현한다.
마지막 값에 done 이 true 로 되는데 value 값과 done 값이 모두 참이 되면 Iterator 의 리턴 값이 된다.
2
3
Q. done: false;
-> ; 객체 문법 오류가 있습니다
let count = -1;
let movieIter = {
// 이 객체 안에는 1개의 Symbol.iterator 프로퍼티가 있다.
// Symbol 을 통해 iterator 의 Unique함을 보장할 수 있다.
[Symbol.iterator]: function(movie){
return {
// next () 함수를 통해 순회하므로 next 를 구현 해준다.
next: () => {
count++;
switch (count) {
case 0:
return {
value: movie.title,
done: false,
}
case 1:
return {
value: movie.year,
done: false,
}
case 2:
return {
value: movie.director,
done: false,
}
case 3:
return {
value: undefined, done: true
}
default:
return {
value: undefined, done: true
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Generator
# by 형욱
- 함수 표현식을 익명으로 하지 않아도 되는 것을 알게 되었습니다.
let P=function* Problem() {... }
- MDN 함수표현식
- 유명(named) 함수 표현식
- 함수 몸통 안 쪽에서 현재 함수를 참고하고 싶을 때
- name 속성을 가진다.
- 익명 함수 표현식
- 유명(named) 함수 표현식
- MDN 함수표현식
# to 형욱
/*제너레이터 정리
function* 선언 (끝에 별표가 있는 function keyword) 은 generator function 을 정의하는데, 이 함수는 Generator 객체를 반환합니다.
함수를 정의하는 방법은 함수 선언과 함수 표현식 2가지가 있다. => 함수를 정의하려면 2가지 방법을 써야한다.
쓴이는 함수선언식으로도 시도를 해봤으나 이는 제대로 결과가 나오지않는것을 알수있다.
*/
function* NoProblem() {
let i = 10;
while (i<13) {
yield i++;
}
}
let NP =NoProblem();
let P=function* Problem() {
let i = 10;
while (i<13) {
yield i++;
}
}
console.log(typeof NP, typeof P()); //object object
console.log(NP.next()); //{ value: 10, done: false }
console.log(NP.next()); //{ value: 11, done: false }
console.log(P().next()); //{ value: 10, done: false }
console.log(P().next()); //{ value: 11, done: false }
console.log(NP);
console.log(P());
/* 맨아래 NP,P()의 결과를 보면
NoProblem {<suspended>}
__proto__: Generator
[[GeneratorLocation]]: example.js:4
[[GeneratorStatus]]: "suspended"
[[GeneratorFunction]]: ƒ* NoProblem()
[[GeneratorReceiver]]: Window
[[Scopes]]: Scopes[3]
0: Local (NoProblem) {i: 12}
1: Script {NP: NoProblem, P: ƒ}
2: Global {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
Problem {<suspended>}
__proto__: Generator
[[GeneratorLocation]]: example.js:9
[[GeneratorStatus]]: "suspended"
[[GeneratorFunction]]: ƒ* Problem()
[[GeneratorReceiver]]: Window
[[Scopes]]: Scopes[3]
0: Local (Problem) {i: undefined}
1: Script {NP: NoProblem, P: ƒ}
2: Global {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
이를 통해 i의 값이 NP는 12로 되어있고 P()는 undefined로 결과가 나오는 것을 통해 함수선언문으로는 불가능하다는 것을 알수있다. (비슷해보이지만)
따라서 Generator함수를 쓰기위해서는 함수 선언과 함수 표현식 2가지를 사용해야한다. (함수선언식으로는 정상적 next()사용이 어렵다 생각)
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
A. 해석
case1
function* NoProblem() { let i = 10; while (i<13) { yield i++; } } let NP = NoProblem(); NP.next(); // {value: 10, done: false} NP.next(); //{value: 11, done: false} NP.next(); // {value: 12, done: false} NP.next(); // {value: undefined, done: true}
1
2
3
4
5
6
7
8
9
10
11
12case2
let P = function* Problem() { let i = 10; while (i<13) { yield i++; } }; P().next(); // {value: 10, done: false} P().next(); // {value: 10, done: false} P().next(); // {value: 10, done: false}
1
2
3
4
5
6
7
8
9
10
case1 는 generator 함수를 호출해 받은 iterator 객체를 변수에다 할당하여 사용하기 때문에 하나의 공간을 사용한다.
case2 는 P().next();
를 호출할 때마다, 공간을 새로 만들어서 쓰기 때문에, P().next();
들은 각각 다른 공간을 사용하는 것이다.
그리고 함수를 호출만 했기 때문에 statement 가 끝나면 공간이 사라지게 되는 것이다.
따라서 아래와 같이 사용해야 한다.
let p = P(); // 호출 후 P 가 반환하는 iterator 객체를 p 에 할당.
p.next(); // {value: 10, done: false}
p.next(); // {value: 11, done: false}
p.next(); // {value: 12, done: false}
p.next(); // {value: undefined, done: true}
2
3
4
5
# to 정웅
Q. 코드스피츠 들으면서 JS 엔진이 동작하는 것은 변화하기 때문에. 스코프 체인방식도 과거의 개념이며,
// return undefined 👉 JS 는 반환 값이 없으면 자동으로 undefined 를 반환
// 5) 에서 return 값이 반환 되면 done 이 true 로 바뀐다.
여기에 있는 동작 방식의 내용도 과거의 동작 방식 일수 도 있다는 추측이 듭니다. 혹은 같은 말을 다르게 서술한 거라고 볼 수 있는데요.
제 글을 보면 아시겠지만, 코드스피츠 맹선생님이 설명하는 바로는 { done: false, value: 1 }
이런 형태의 객체를 IteratorResultObject
이라고 하는데, generator 루틴을 빠져나올 때 { done: true, value: undefined }
를 반환한다고 하였습니다.
// 1) genny 라는 generator 선언
// function * 👉 Generator 로 사용됨을 의미
function* genny() {
yield 'a';
yield 'b';
// return undefined 👉 JS 는 반환 값이 없으면 자동으로 undefined 를 반환
}
// 2) genny 라는 generator 로 iter 라는 iterator 생성
// iterator 는 next 라는 built-in function 제공
let iter = genny();
console.log(iter.next()); // 3) { value 'a', done : false }
console.log(iter.next()); // 4) { value 'b', done : false }
console.log(iter.next()); // 5) { value : undefined, done : true }
// 5) 에서 return 값이 반환 되면 done 이 true 로 바뀐다.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# to 유림
Q. generator 함수를 호출할 때마다 iterator 가 만들어 진다. 하지만 generator 는 iterable 이 아닌데 iterator 객체를 반환 할 줄 안다. for..of 를 쓸 수 없다. 하지만 generator 가 반환한 iterator 객체는 iterable 이기도 하다. for..of 을 쓸 수 있다.
Generator 함수는 iterable 객체를 반환하는 특별한 형태의 함수이다.
,
Generator 함수를 호출하면 iterable 객체가 반환되고