LoginSignup
6
3

More than 3 years have passed since last update.

JavaScript: Object.prototypeにメソッドを生やしてパイプライン演算子っぽくしてみた

Last updated at Posted at 2019-05-14

まず最初に言っておきます。ビルトインオブジェクトにプロパティ、メソッドを追加するのは、たいがい Bad mannerです。やらないでください。

と ことわった上でちょっとだけ遊んでみました。
今現在、|> はまだ普通には使えないので、代わりといっては何ですが、パイプライン演算子っぽいものを作ってみます。

const _ = Symbol("pipeline")
Object.prototype[_] = function(f){return f(this)}

はい完成。
Object.prototype に [_] というメソッドを追加してみました。自分を関数に適用した結果を返す、みたいなことです。
名前は既存のプロパティ、メソッドとかぶっちゃいけないので、Symbolを使ってみました。

こんな使い方です。

console.log(
  [0,1] 
    [_] (x=>x.map(e=>e*2))               // [0, 2]
    [_] (x=>x.reduce((acc,e)=>acc+e,0))  //  2
    [_] (x=>x===0)                       // false
    [_] (x=>!x)                          // true
);  // 'true'

ほーらパイプライン演算子に見えてきた!

おしまい。

くれぐれも本番では使いませんように。

「おかしいよ」「そんなことしたら、こんな悪いことがあるぞ」というようなお叱りのコメント、おまちしております。

追記: これのダメなところと対策

もうちょっと遊んでみます。

ダメなところ

Object.prototype にメソッドを付ければ、すべてのモノに使える、と思ったのが間違いの元。

null[_]  // TypeError: Cannot read property 'Symbol(pipeline)' of null
undefined[_]  // TypeError: Cannot read property 'Symbol(pipeline)' of undefined

null と undefined には使えませんでした。
なので、実行時にこの疑似パイプラインのチェーンの途中にこれらの値が現れると、エラーで止まる、ということになります。

対策1 : nullとundefinedを適宜、別のものにすりかえる

const thingNull = Symbol("null")
const thingUndefined = Symbol("undefined")
const checkFail = x =>
  x===null ? thingNull
  : x===undefined ? thingUndefined
  : x

const _ = Symbol("pipeline")
Object.prototype[_] = function(f){
  const thingThis = this.valueOf()
  return checkFail(
    f(
      thingThis===thingNull ? null
      : thingThis===thingUndefined ? undefined 
      : thingThis
    )
  )
}

こうしておくと

checkFail(undefined) [_] (x=>x);  // Symbol(undefined)
checkFail(null) [_] (n=>n===null);  // true

のように、最初だけ null/undefined かどうか、チェック checkFail() が必要ですが、あとは適宜ダメなところは別のオブジェクト thingNull/thingUndefined にすりかえながら計算を続行してくれます。

対策2 : null, undefined, NaN をまとめて、「計算が失敗した」ことにする

const Nothing = Symbol("Nothing")
const checkFail = x =>
  x===null || x===undefined || Number.isNaN(x) ? Nothing : x

const _ = Symbol("pipeline")
Object.prototype[_] = function(f){
  const thingThis = this.valueOf()
  return (thingThis===Nothing)?  Nothing
  : checkFail(f(thingThis))
}

対策1と似ていますが、 null/undefined/NaN が現れたら 計算の失敗 Nothing ということにして 以降は計算しないで Nothing を返す、というところが違います。

checkFail(undefined) [_] (x=>x);  // Symbol(Nothing)
checkFail(null) [_] (n=>n===null);  // Symbol(Nothing)
checkFail( 1 ) [_] (x=>NaN);  // Symbol(Nothing)

これで、途中に null/undefined が現れても大丈夫になりました。

おしまい。
くれぐれも本番では使いませんように。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3