비동기 처리에 이어서..
propery attribute
에는 [[enumerable]]
라는 속성이 있다.[[enumerable]]
은 프로퍼티의 열거 가능여부를 나타낸다.[[enumerable]]
이 true
인 객체는 프로퍼티의 요소를 열거할 수 있다.[[enumerable]]
이 true
이어야 한다.for..in
과 for..of
에 대한 문법. 대상이 enumerable
해야 함을 알 수 있다.왜 생겨났는가 ?
다양한 데이터 공급자 ( array
, string
, map/set
, DOM Collection
...) 로 부터 순차적인 데이터를 가져오기 위한 효율적인 규칙이 필요해서 탄생.
(저 예시들의 데이터를 불러올 때마다 각자 다른 규칙과 문법이 쓰인다고 생각하면 정말 비효율적이다.)
'반복' 에 관한 프로토콜들. 2 종류가 있다.
iterable protocol
: 순회 가능 한.
iterator protocol
: 순회 기능이 있는.
[Symbol.iterator]
(=@@iterator
) 라는 메서드가 있어서,
[Symbol.iterator]
를 호출하면iterator
객체를 반환한다.
iterable
한 객체" 라고 한다.직관적으로 이해하기 위해 "순회 기능이 있는" 으로 표현했다.
명시적 규칙은 다음과 같다.
next()
메서드를 가지고 있으며,next()
호출 시,
{value, done}
형태의Iterator Result
를 반환한다.
value
에는 현재 순회하는 위치의 값을 나타내며,
done
은 해당 객체의 프로퍼티를 모두 순회했는지의 여부를 나타낸다.
위 규칙을 만족하는 객체를 "iterator
객체" 라고 한다.
Well Formed Iterable
객체라고 한다.iterable 한 객체
의 [Symbol.iterator]()
를 실행하여,iterator
를 생성하여 사용한다. (객체가 이터레이터화 되어 반환됨)iterator
는 next()
메서드를 통해 사용할 수 있다.const arr = [1, 2, 3]
const iter = arr[Symbol.iterator]() // Array Iterator 객체 생성
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
[Symbol.iterator]()
로 이터러블한 배열을 가지고 이터레이터 객체를 생성value
와 완료여부 done
을 가진) 한 다음, 전개연산자 (...)
를 사용하게 되면, 이터러블 객체의 이터레이터를 순회하면서, next()
로 각 요소를 하나씩 받아와 나열한다.( = 함수를 이터레이터로 만들기 )
( = 심지어 평가되기를 미뤄둔 이터러블 이터레이터 )
( = 그것이, 제너레이터 )
yield
를 사용한다.yield
를 사용하기 위해서는 함수를 generator function
로 바꾼다.generator function
는 function *
으로 표기한다.// 제너레이터 함수선언문
function* genDecFunc(){
yield 0;
}
// 제너레이터 함수 표현식
const genExpFunc = function * (){
yield 0;
};
// 제너레이터 메서드
const obj = {
* genObjMethod(){
yield 0;
}
};
// 제너레이터 클래스 메서드
class genClass{
* genClassMethod(){
yield 0;
}
}
iterator
이면서, iterable
이다.next()
메서드로 yield
를 넘길 수 있다.'첫 yield 전 까지'
의 실행은 next() 메서드가 호출되어야 비로소 실행.next()
로 yield
이후를 실행, 실행한 값을 value
로 받음,
next()
는 {value, done}
형태의 iteratorResult
를 반환한다.
yield
는 한 박자 늦는 return
이라고 생각하면 될 듯 하다.
- 제너레이터 함수는 제너레이터 객체를 만들어 주는 역할일 뿐이고,
- 함수 호출자가 next()로 제너레이터 객체의 값을 하나씩 넘기면서 실질적으로 활용한다.
지연평가
, Lazy Evaluation
이라고 한다." 계산은 나중에 한다 "
Lazy Evaluation
: 은 계산의 결과값이 필요할 때까지 "계산을 늦추는 기법".
undefined
대신지연평가
란,// 일반적인 함수
function originalFunction(size){
function newArr(n) {
let i = 1;
const res = [];
while (i < n) res.push(i++);
return res;
}
let sum = 0;
const numArr = newArr(size);
for(let i = 0; i < numArr.length; i++){
if(numArr[i] % 2 === 0){ sum += numArr[i]; }
else if(sum >= 100) break;
}
return sum
}
// 지연평가 함수로 작성
function lazyFunction(size){
function * numArr(n){
let i = 1;
while (i < n) yield i++;
}
let sum = 0;
for(const item of numArr(size)){
if(item % 2 === 0){ sum += item; }
else if(sum >= 100) break;
}
return sum;
}
console.time('originalFunction 의 소요시간');
console.log("originalFunction : ", originalFunction(10000000));
console.timeEnd('originalFunction 의 소요시간');
console.time('lazyFunction 의 소요시간');
console.log("lazyFunction : ", lazyFunction(10000000));
console.timeEnd('lazyFunction 의 소요시간');
originalFunction : 110
originalFunction 의 소요시간: 445.461ms
lazyFunction : 110
lazyFunction 의 소요시간: 0.366ms
// 일반 반복문으로 작성한 피보나치 수열
const originalFibo = function () {
let [pre, cur] = [0, 1];
while (true) {
[pre, cur] = [cur, pre + cur];
if (cur > 10000) break;
console.log(cur);
}
}
originalFibo()
//------------------------------------------
// 제너레이터를 활용한 피보나치 수열
const generatorFibo = function* () {
let [pre, cur] = [0, 1];
while (true) {
[pre, cur] = [cur, pre + cur];
yield cur;
}
}
for (const num of generatorFibo()) {
if (num > 10000) break;
console.log(num)
}
originalFibo
에서 console.log
를 안에서 찍고, break
문을 걸어줘서 그렇지, 피보나치의 수를 구하는 자체의 함수 만으로는 무한하게 돌아버린다..generatorFibo
피보나치 수열을 구하는 함수는 무한이지만, 외부에서 제어가 가능하기 때문에 활용이 가능하다.(작성 중)
generator
와Promise
를 조합해서 쓰면async/await
형태가 된다.
Promise
가 실행되서 반환된 Promise 객체
는 then()
등을 통해 그 다음단계로 넘어가는데, generator
의 next()
를 이용해 각각의 promise
가 한 단계 넘어 갈 때마다 변수로 그 결과를 받아두면, async
함수 안에서 const aaa = await promiseObj
형태로 변수에 저장하는 것과 같다.
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Iteration_protocols
https://ko.wikipedia.org/wiki/%EB%8A%90%EA%B8%8B%ED%95%9C_%EA%B3%84%EC%82%B0%EB%B2%95- 모던 자바스크립트 딥다이브 ( 34.이터러블, 46.제너레이터와 async/await )
- https://armadillo-dev.github.io/javascript/what-is-iterable-and-iterator
- https://www.youtube.com/watch?v=FxBMhEy0aSk
- 프로퍼티 어트리뷰트
- Symbol