const a = 10
const add10 = a => a + 10
const res = add10(a)
const add5 = a => a +5
add5
add5(5)
const f1 = () => () => 1
const f2 = f1()
고차함수 : 함수를 값으로 다루는 함수
함수를 인자로 받아서 실행하는 함수
apply
const apply1 = f => f(1)
const add2 = a => a + 2
apply1(add2) // 3
times
const times = (f, n) => {
let i = -1
while(++i < n){
f(i)
}
}
times(console.log, 3) // 1, 2, 3
이러한 프로그래밍을 어플리케이티브 프로그래밍이라고도 함
함수를 만들어서 리턴 (클로저 만들어 리턴)
const addMaker = a => b => a + b
const add10 = addMaker(10)
add10(10) // 20
1) Array
const arr = [1, 2, 3]
for(const a of arr) console.log(a)
Array는 key로 접근해서 내부 요소 조회
2) Set
const set = new Set([1, 2, 3])
for(const a of set) console.log(a)
Set은 key로 접근하지 않음 -> for문으로 순회하는 것임 아님
3) Map
const map = new Map([["a", 1], ["b", 2], ["c",3]])
for(const a of map) console.log(a)
arr[Symbol.iterator] = null
을 할 경우 이터러블이 아니라고 에러남
Array, Map, Set은 이터러블/이터러블 프로토콜을 따른다.
이터러블이란 이터레이터를 리턴하는 [Symbol.iterator]()
를 가진 값
이터레이터란 {value, done}
이라는 객체를 리턴하는 next()
를 가진 값
let iterator = arr[Symbol.iterator]()
iterator.next() // {value:1, done:false}
iterator.next() // {value:2, done:false}
iterator.next() // {value:3, done:false}
iterator.next() // {value:undefined, done:true}
이터러블/이터레이터 프로토콜은 이터러블을 for..of, 전개 연산자 등과 함께 동작하도록 하는 규약
const iterable = {
[Symbol.iterator](){
let i = 3
return {
next(){
return i===0 ? {done:true}:{
value:i--, done:false
}
}
}
}
}
let iterator = iterable[Symbol.iterator]();
for(const a of iterable) console.log(a) //1, 2, 3
여기까지는 ES6에서 제공하는 이터레이터와 비슷하다. 다시 기존의 이러레이터를 보면
const arr2 = [1, 2, 3]
let iter2 = arr2[Symbol.iterator]()
// 이터레이터를 미리 한 번 실행함
iter2.next()
// 그리고 for of 를 진행
for(const a of iter2){
console.log(a) // 2,3
}
// 먼저 진행된 1을 제외하고 리턴
잘 구현 된 이터레이터는 실행을 진행하고, 멈추고를 자유롭게 할 수 있다.
즉, iter2[Symbol.iterator] === iter2
가 true일 때 잘 만든 이터레이터다.
다시 사용자 정의 이터러블로 넘어가서
const iterable = {
[Symbol.iterator](){
let i = 3
return {
next(){
return i===0 ? {done:true}:{
value:i--, done:false
}
},
[Symbol.iterator](){
return this
}
}
}
}
[Symbol.iterator]()
를 리턴할 때 자기 자신도 리턴하게 한다.
-> DOM객체 순회 가능한 것도 웹 API 등도 이터러블 규약을 따르고 있어서
즉, 이터레이터를 리턴하는 함수
function *gen(){
yield 1;
yield 2;
yield 3;
// done:true 일 때 리턴함
return 100
}
let iter = gen()
iter.next()
iter.next()
iter.next()
// for of 결과와 동일함
어떠한 값도 제너레이터를 통해 순회 가능하게 만들 수 있다.
제너레이터로 홀수만 발생시키는 함수
// 실행할 때 마다 i를 증가시킴
function* infinity(i = 0) {
while (true) {
yield i++;
}
}
// iter를 돌다가 l를 만나면 멈춤
function* limit(l, iter) {
for (const a of iter) {
yield a;
if (a === l) return;
}
}
function* odds(l) {
for (const a of limit(l, infinity(1))) {
if (a % 2) yield a;
}
}
L.map
이런 식으로 함수명에 L.을 붙임// range
const range = (l) => {
let i = -1;
let res = []
while(++i < l){
res.push(i)
}
return res
}
// L.range
const L = {}
L.range = function *(l) {
let i = -1
while(++i < l){
yield i
}
}