javascriptでパイプライン演算子を使いたい
こういうやつ。
text = '{"0": "a", "1": "b"}';
text |> JSON.parse |> Object.entries |> (a=>new Map(a)) |> console.log;// これ
// console.log(new Map(Object.entries(JSON.parse(json)))); と同等
まだステージ1で使えないので、代替を考えてみる。
関数で実装
まずは素直に、初期値と関数を渡すと返り値を返すだけの関数を実装してみる。
const chain = (start, ...fns)=>{
let result = start
for (const fn of fns) {
result = fn(result)
}
return result
}
使ってみる。
const result = chain(text,
JSON.parse,
Object.entries,
a=>new Map(a)
)
console.log(result)
シンプルで見通しがいい。もうこれでいいんじゃないかな。
メソッドチェーン(もどき?)
せっかくなので、別の方法でも実装してみる。
const start = (val)=>{
return {
chain(fn) {return start(fn(val))},
end() {return val}
}
}
const result = start(text)
.chain(JSON.parse)
.chain(Object.entries)
.chain(a=>new Map(a))
.end()
console.log(result)
これはこれで、分かりやすくて良いと思う。
prototype拡張
直接メソッドチェーンしてみよう。
Object.defineProperty(Object.prototype, '_chain', {
configurable: false,
enumerable: false,
value: function(fn){return fn(this)}
});
const result = text
._chain(JSON.parse)
._chain(Object.entries)
._chain(a=>new Map(a))
console.log(result)
Objectのprototypeを直接拡張するのは弊害が大きすぎるので、絶対やめましょう。prototype拡張を行うライブラリを読み込んでいる場合、名前がバッティングした時に死にます。
prototype拡張 その2
symbolを使う方法。
const chain = Symbol('chain');
Object.defineProperty(Object.prototype, chain, {
configurable: false,
enumerable: false,
value: function(fn){return fn(this)}
});
const result = text
[chain](JSON.parse)
[chain](Object.entries)
[chain](a=>new Map(a))
console.log(result)
symbolを用いてprototype拡張すれば、ライブラリ等とバッティングせずに済むため安全安心。
但し、使いやすくは…ない。
Array.prototype.map()使用
一旦配列に入れると、配列操作系の関数を使うことができる。
const result = [text]
.map(JSON.parse)
.map(Object.entries)
.map(a=>new Map(a))
[0]
console.log(result)
配列から取り出すために、最後に[0]を付ける必要がある。いつか書き忘れそうで怖い。
Array.prototype.reduce()使用
reduceも使える。今度は関数の方が配列に入っているので注意。
const result = [
JSON.parse,
Object.entries,
a=>new Map(a)
].reduce((val, fn)=>fn(val), text)
console.log(result)
そろそろパイプライン演算子とは程遠くなってきている。
Promise使用
Promiseのthen()の引数には関数を渡している。この仕様を、関数呼び出しのためだけに利用してみる。
//返り値を使用しない場合
new Promise(r=>r(text))
.then(JSON.parse)
.then(Object.entries)
.then(a=>new Map(a))
//返り値を受け取る場合
(async function(){
const result = await new Promise(r=>r(text))
.then(JSON.parse)
.then(Object.entries)
.then(a=>new Map(a))
console.log(result)
})()
返り値を使いたいときに.then()で繋げるか、async関数内でawaitする必要がある。
非同期処理と関係ないところにPromiseをいきなり使ったら混乱しそうだなとは思う。