Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8862

リファクタリングに使える俺的JavaScript小技テクニック集5選

$
0
0

JavaScriptとちょっとしたリファクタリングにおすすめのテクニックを晒します。

  • 俺的ラインナップ
    • ① if文よりも&&演算子
    • ② nilガード
    • ③ reduce
    • ④ enumもどき
    • ⑤ ピュアなObject

①if文よりも&&演算子

よくあるif文。

constarray=[]if(isHoge){array.push("hoge")}if(isFuga){array.push("fuga")}

上記の文を &&演算子を使うとすっきり書けます。

constarray=[]isHoge&&array.push("hoge")isFuga&&array.push("fuga")

&&演算子は左側がtrueの場合は右側が評価されるので上記のように書くことができます。
なお、配列での処理を例に挙げましたが、オブジェクトでの処理でも活用できます。

constobj={}isHoge&&Object.defineProperty(obj,"hoge",{value:hoge})isFuga&&Object.defineProperty(obj,"fuga",{value:fuga})

余談ですが、都度 Object.definePropertyを使うのも冗長なので、関数化をすれば次のように更に簡潔に記述できます。

// カリー化のテクニックを使っていますconstdefineProp=(obj,key,value)=>{return(key,value)=>{returnObject.defineProperty(obj,key,{value,writable:false,// readonlyenumerable:true,// in演算子などでプロパティを列挙させる})}}constobj={}constdefinePropObj=defineProp(obj)isHoge&&definePropObj("hoge",hoge)isFuga&&definePropObj("fuga",fuga)

②nilガード

nilガードをご存知でしょうか?Rubyを普段書いている方ならご存知かもしれません。
どの言語も同じだと思いますが、nullのようなもの(Rubyなら nil, JavaScriptなら nullundefinedなど)は予期せぬバグの元となります。

Rubyでは意図せず nilが変数に入らないように、nilガードというテクニックがあります。

hoge=nil# hogeがnilなら"hoge"が代入されるhoge||="hoge"phoge#=> "hoge"fuga="fugafuga"fuga||="fuga"phoge#=> "fugafuga"

JavaScriptでも ||演算子を使えばnilガードと似たような文を再現することができます。

lethogehoge=hoge||"hoge"console.log(hoge)// => "hoge"letfuga="fugafuga"fuga=fuga||"fuga"console.log(fuga)// => "fugafuga"

hoge = hoge || "hoge"の文ではまず右辺が評価されます。
||演算子は左側がfalsyの時に右側が評価されるので、もし hogenullundefinedの場合は右側の "hoge"が評価され、変数 hogeに代入されます。

また余談ですが、上記のような ||を用いたテクニックはnilガードでなくとも役に立つので、覚えておくと便利です。
実際、有名なJavaScriptのフレームワークであるReactのソースでも下記のようにテクニックを使っている箇所がみられました(何やってるコードかは微塵もわかりません笑)。

https://github.com/facebook/react/blob/50393dc3a0c59cfefd349d31992256efd6f8c261/packages/react-devtools-shared/src/backend/renderer.js#L436

③reduce

reduceはJavaScriptのArrayに標準で組み込まれている関数です(MDN)。ぶっちゃけ、存在は知っていても「使い方ようわからん」「使わんでも生きていける」と思う方も多いかもしれません。しかし、reduceほど便利な関数はありません。

reduceを使えば、例えば次のようなコードを書けます。

// 年齢ごとで何人いるかを算出します。constkimetsu=[{name:'竈門 炭治郎',age:15},{name:'竈門 禰豆子',age:14},{name:'我妻 善逸',age:16},{name:'嘴平 伊之助',age:15},]// 1. ありがちな書き方constoutput1={}kimetsu.forEach(member=>{if(!(member.ageinoutput1)){output1[member.age]=1return}output1[member.age]++})console.log(output1)// => {14: 1, 15: 2, 16: 1}// 2. reduceを使った書き方constoutput2=kimetsu.reduce((result,member)=>{if(!(member.ageinresult)){result[member.age]=1returnresult}result[member.age]++returnresult},{})console.log(output2)// => {14: 1, 15: 2, 16: 1}

1. ありがちな書き方では空のオブジェクトを宣言する必要がありますが、 2. reduceを使った書き方をご覧いただければわかるように、空のオブジェクトを宣言しなくとも変数を初期化することができます。

他にも下記のように全員の年齢を足すことも reduceでできます。

constsumAge=kimetsu.reduce((result,member)=>{result+=member.agereturnresult},0)console.log(sumAge)// => 60

その他にもreduceは覚えておくと使い所も多く応用も効くのでおすすめです。MDNのドキュメントに幾つか例があるので興味あればぜひ読んでみてください。

④enumもどき

「列挙型」としてJavaやPythonなど、様々な言語でサポートされているenumですが、JavaScriptでもenumに似たようなものを再現することができます。

// JavaScriptにおけるenumっぽいものconstAnimal=Object.freeze({DOG:Symbol(),CAT:Symbol(),BIRD:Symbol(),})constdog={type:Animal.DOG,name:"ポチ"}console.log(dog.type===Animal.CAT)// => false

Object.freezeを使うことで対象のオブジェクトを変更不可能にします。
さらに Symbolを利用することでプログラム上で一意であることを担保します。

Animalをexportすることによって dog.type === "dog"のような保守性の低いコードを散財させることを防ぐことができます。

⑤ピュアなObject

ピュアなObjectとは、純粋に key-valueのみで構成されるオブジェクトです(Javaで言うところMapのような。なお、「ピュアなObject」は私が勝手に呼んでいるだけで、世間一般的な用語じゃないです)。
オブジェクトを宣言する時には var hoge = {}と宣言していますが、実はこれはピュアなオブジェクトではありません。どういうことでしょうか。

試しにvar hoge = {}を宣言してみると、hogeの中身は次のようになります。

空オブジェクトの宣言.png

hogeの中によくわからないプロパティが紛れ込んでいます。
これは、var hoge = {}で宣言すると、Objectのクラスを継承したオブジェクト(正確にはObjectをプロトタイプとしたオブジェクト)が生成されてしまうためです。

これは何が問題でしょうか?ずばりパフォーマンスに影響を与えます。
例えば下記のコード。

if("xxx"inhoge){// 処理}

この in演算子はプロトタイプチェーンを遡って全てのオブジェクトのプロパティをチェックします。
先ほどのキャプチャの例で言うならば、constructorhasOwnPropertyまでチェックしてしまいます。

純粋に key-value のオブジェクトを生成するには次のようにします。

// 1. ECMA2015の書き方consthoge=Object.create(null)// 2. ECMA2015以降の書き方consthoge=newMap()

1. ECMA2015の書き方ではnullをプロトタイプとするオブジェクトを生成することでピュアなオブジェクトを生成できます。

一方、ECMA2015以降ならばMapが利用できます。

なお、Object.create(null)で生成したオブジェクトは下記のキャプチャのようになります。

ピュアなオブジェクトの生成.png

まとめ

リファクタに使えそうな5つの俺的JavaScript小技を紹介しました。
特に書籍を参考にしたわけではないオレオレなテクニックだったのですが、参考にしていただけると嬉しいです!
他にも小技テクニックあればコメントいただけると幸いです。


Viewing all articles
Browse latest Browse all 8862

Trending Articles