이전 포스팅 참고
이번엔 Partial.js 의 약간은 잡기능(?) 에 대해 알아보도록 하겠습니다.
- 고차 함수의 보조 함수에서 더 많은 인자 사용
Partial.js 의 주요 고차 함수들에게는 지난 포스팅에 적은 비동기 제어 외에도 Underscore.js, Lodash 의 고차 함수와는 다르게 동작하는 부분이 있습니다. 그 중 하나인 보조 함수에서 더 많은 인자를 사용하는 부분을 예시 코드로 보도록 하겠습니다.
const _ = require('underscore');
function test1() {
const a = 1;
const b = 1;
return _.map([1, 2, 3], val => val * a - b);
}
console.info(test1()); // [-1, 0, 1]
먼저 Underscore.js 에선 클로저를 사용해서 a, b 를 기억하게 만들고 이를 _.map 에서 사용하도록 코드를 작성해야 합니다.
const _ = require('partial-js');
const test1 = _.map(1, 2, [1, 2, 3], (a, b, val) => val * a - b);
console.info(test1); // [-1, 0, 1]
Partial.js 에서 _.map 은 인자를 여러 개 넘기면 iteratee 에도 인자로 넘겨주고, 이를 사용할 수 있습니다.
코드를 더욱 깔끔하게 만들어주는 장점이 있습니다.
- _.all / _.spread
이 두 함수는 파이프라인과 사용할 때 유용합니다. 예시 코드로 보도록 하겠습니다.
_.go(10,
_.all(
a => a + 5,
a => a - 5,
a => a * 5,
),
console.info); // 15 5 50
_.all 함수는 모든 인자를 모든 함수들에게 동일하게 전달합니다. 따라서 위 함수에서 각 세 함수의 a 에는 전부 10이 들어가게 됩니다.
_.go(_.mr(10, 9, 8),
_.spread(
a => a + 5,
a => a - 5,
a => a * 5,
),
console.info); // 15 4 40
_.spread 함수는 받은 인자를 하나씩 함수에 나눠줍니다. 따라서 여기선 세 함수에 각각 10, 9, 8 이 들어가게 됩니다.
예시를 위해 억지로 _.mr 함수를 사용했지만, 위의 _.all 과 함께 이런식으로 사용할 수도 있습니다.
_.go(10,
_.all(
a => a + 5,
a => a - 5,
a => a * 5,
),
_.spread(
a => a + 5,
a => a - 5,
a => a * 5,
),
console.info); // 20 0 250
_.all 과 _.spread 는 동기로만 동작하지만 _.go, _.pipe 등의 파이프라인 함수와 함께 비동기 상황에서도 유용히 사용할 수 있습니다.
- _.indent
자바스크립트에선 스코프라는 개념이 있어서, 자식 스코프에선 부모 스코프의 지역 변수를 참조할 수 있씁니다.
이러한 접근 방식이 파이프라인 내에서도 필요한데, 이를 가능하게 해주는 함수가 _.indent 입니다.
_.indent 함수는 이름처럼 _.indent 가 중첩될 때마다 this 와 arguments 를 한 단계씩 안으로 들여쓰는 컨셉을 갖고 있습니다.
const f1 = _.indent(
function() {
console.info(this, arguments); // { parent: global, arguments: [1, 2] } [1, 2]
return 'test1';
},
function() {
console.info(this, arguments); // { parent: global, arguments: [1, 2] } ['test1']
}
);
f1(1, 2);
_.indent 는 _.pipe 처럼 함수를 리턴하는 파이프라인입니다.
저는 Node.js 환경에서 실행시켰기 때문에 parent 가 global 로 나왔지만, 브라우저 환경에선 Window 로 나올 것입니다.
여기서 찍은 두 console.info 에는 arguments 의 차이가 있습니다.
첫 번째 함수는 이 파이프라인의 첫 함수이므로 f1(1, 2) 을 통해 넘겨진 인자 [1, 2] 가 arguments 에 들어옵니다.
두 번째 함수에선 이전 함수가 'test1' 을 리턴하기 때문에 ['test1'] 이 arguments 로 들어오게 됩니다.
다만 두 함수에서 this 가 들고있는 값은 똑같은 것을 볼 수 있습니다.
파이프라인에서 코드를 짜다가 중간에 있는 함수에서 최초로 받은 인자를 알고 싶을 경우, _.indent 를 사용하게 되면 어디서든 this.arguments 를 통해 최초 인자들에 접근할 수 있습니다.
물론 _.indent 를 사용하지 않아도 클로저를 사용해 충분히 해결 가능하지만, 좀 더 쉬운 방법이긴 합니다.
_.indent 의 this 는 한 번의 파이프라인 사용 후 휘발되는 this 입니다.
Express.js 에서 req 나 res 를 사용하듯이 값을 이어주는 식으로 사용할 수도 있고, 함수를 실행할 때마다 새로 생겼다가 사라지는 this 이므로 부수 효과가 최소화되며 메모리 사용에도 문제가 없습니다.
this 의 등장으로 인해 약간 의구심이 들 수 있는 부분을 예시와 함께 보도록 하겠습니다.
const f2 = _.indent(
function(a) {
this.b = a + 10;
},
function() {},
function() { console.info(this.b); });
f2(5); // 15
f2(10); // 20
이런 코드를 보면 this 의 값을 변경하고 있기 때문에, 함수형 프로그래밍과는 본질이 다르게 상태를 변경해 나가는 프로그래밍이라는 생각이 들 수 있습니다. 하지만 _.indent 에서의 this 는 앞서 얘기한 것 처럼 작은 함수들을 모아 만든 하나의 파이프라인에서 만들어지는 this 이므로 외부 상태라고 볼 수 없으며 지속되는 this 가 아니기에 부수 효과 없는 코드 작업이 가능합니다.
const test1 = _.indent(
function(a) {
this.b = a + 10
},
_.indent(
function() {
this.b = 30;
console.info(this.b); // 30
console.info(this.parent.b); // 20
},
function() {
console.info(this.parent.arguments); // [10]
},
)
);
test1(10);
위 예시를 통해 _.indent 를 두 번 이상 사용할 때 this 의 구조를 알 수 있습니다.
this 의 parent 및 arguments 를 통해 접근이 가능한데, 사실 이 방법은 언제 어디서든 값을 변경할 수 있다는 말도 되므로 값을 불변적으로 다루는 것이 중요합니다. 이 부분은 다른 포스팅에서 얘기해보도록 하겠습니다.
- _.async
지금까지 얘기한 것 처럼 _.go, _.pipe, _.indent 는 파이프라인 내부의 함수에서 비동기 결과가 나올 경우 비동기 제어를 시작하도록 구현되어 있습니다. _.async 는 내부 함수의 결과와 상관없이 무조건 비동기를 일으키고 싶을 때 사용합니다.
_.go.async(1, a => a).then(console.info);
console.info(2);
// 2
// 1
- _.branch : 비동기 건너뛰기
이런 방법을 써야할 경우가 언제일지 구체적인 예시는 떠오르지 않지만, _.go 를 이용하면서 중간에 비동기 결과가 나오더라도 비동기 제어를 하지 않는 방법이 있습니다.
_.go(20,
_.branch(
a => {
return new Promise(resolve => resolve(a + 10));
},
a => {
console.info(a);
return a * a;
},
console.info,
),
console.info);
// 20
// 30
// 900
원래대로면 30, 900 이 찍힌 후 20 을 찍도록 내려와야 하지만, 여기선 _.branch 를 사용함으로써 20 이 먼저 찍혔습니다.
_.branch 내부에선 비동기 제어가 되지만 결과를 기다리지 않고 바로 내려옵니다.
딱히 떠오르는 예시는 지금 없지만, 파이프라인을 사용하더라도 동기적으로 결과를 바로 반환해야 하는 함수들과 비동기 함수들이 협업할 경우 _.branch 를 사용할 수 있을 것 같습니다.
도입부에선 Partial.js 의 잡기능(?) 이라고 소개하긴 했지만 꽤 유용한 기능들이며, 개인적으로 _.indent 는 잘 활용할지 모르겠지만 _.all, _.spread, _.branch 와 같은 함수들은 이후 프로그래밍에서 좀 더 재밌는 코드를 만들 수 있지 않을까 기대해봅니다.
'Backend > 함수형 자바스크립트' 카테고리의 다른 글
지연 평가 (2) (0) | 2021.10.23 |
---|---|
지연 평가 (1) (0) | 2021.10.17 |
Partial.js (2) (0) | 2021.10.02 |
Partial.js (1) (0) | 2021.09.25 |
함수 조립 (2) (0) | 2021.09.18 |