Vue.js の<transition-group>コンポーネントを利用する際、フレームワークによって自動生成される CSS クラスが、開発者が設計したカスタムアニメーションと衝突する可能性があります。これを防止するには、css="false"属性を設定し、デフォルトのクラス付与を抑制してください。また、ページ最初のレンダリング時にも要素が既に表示されているため、通常の遷移イベントがトリガーされないケースに対処するため、appearプロパティを用いて初次ロード時のトランジションを明示的に有効化する手法が推奨されます。
数値フォーマットの効率的な実装
伝統的なアプローチでは、桁ごとの区切り処理のためにループ処理が必要でしたが、現代の JavaScript では組み込みメソッドがこれを代替できます。例えば、英語圏の書式で 3 桁ごとにカンマを入力する場合、以下のコードが使用可能です。
value.toLocaleString('en-US')
さらに、漢字の数値表記への変換も同様に実装されています。
value.toLocaleString('zh-Hans-CN-u-nu-hanidec')
配列処理のパフォーマンス改善
配列に対する連鎖的な操作(フィルタリングやマッピング)を行う際、段階ごとに変換結果が新しい配列として作成されるとメモリーオーバーヘッドが発生します。この問題を解消する方法として、入力の各要素に対してすべての変換を順に適用し、一度のループで集約する方法があります。
const targetList = [10, 25, 55, 8, 14, 100]
const isOdd = (num) => num % 2 !== 0
const doubleVal = (num) => num * 2
const lessThanFifty = (num) => num < 50
const addThree = (num) => num + 3
// 従来のチェーン方式(中間データ発生あり)
const chainResult = targetList
.filter(isOdd)
.map(doubleVal)
.filter(lessThanFifty)
.map(addThree)
/*
[ 21, 25 ]
*/
一方、単一のパスで完結させるためのリデューサーアプローチでは、各要素に対してすべてのルールを適用します。
const composeMap = (fn) => (nextReducer) => (arr, item) => nextReducer(arr, fn(item))
const composeFilter = (predicate) => (nextReducer) => (arr, item) =>
predicate(item) ? nextReducer(arr, item) : arr
const optimizedReducer =
composeFilter(isOdd)(
composeMap(doubleVal)(
composeFilter(lessThanFifty)(
composeMap(addThree)(
(arr, v) => [...arr, v]
)
)
)
)
const singlePassResult = targetList.reduce(optimizedReducer, [])
/*
[ 21, 25 ]
*/
限定実行ユーティリティ (once)
関数の実行数を一回に限るためのパターンとして、クロージャを用いた実装があります。
const singletonExecute = (fn) => {
let hasRun = false
return (...params) => {
if (!hasRun) {
hasRun = true
fn(...params)
}
}
}
返された関数内にはプライベートな状態変数が保持されており、外部からは変更不可です。非同期処理を含める場合、完了フラグのリセットタイミングなどに留意する必要があります。
const asyncTask = singletonExecute(async (val) => {
await externalService(val)
})
asyncTask(10) // 実行開始
asyncTask(10) // 何もしない
singletonExecute(async (val) => {
await externalService(val)
})(10) // 独立したクローンが生成されるため再び実行される
カーリング技術の基礎
関数型パラダイムにおける重要な概念の一つがカーリングです。これはハスケル・カリーに因んで命名されました。複数の引数を一つの引数で受け取り、次の引数を返す関数へと再帰的に展開する技術により、引数部分適用が可能になります。
const sumTriple = (a) => (b) => (c) => a + b + c
// 順次呼び出しによる引数バインド
const firstStep = sumTriple(1) // 残りの引数用関数が返る
const secondStep = firstStep(2) // さらに一つの引数用関数
const total = secondStep(3) // 6 が得られる
// 同時呼び出しの場合、関数自体が返ってくるだけ
// sumTriple(1, 2, 3) は期待通りの計算結果を得られない
この構造はモジュール性が高く、再利用しやすい関数の構築を可能にします。
ポイントフリーと純粋性の確認
中間的な関数定義を省略するスタイルは「ポイントフリー」と呼ばれます。例えば、API からのレスポンス処理関数をそのまま通さずにチェーンに渡すことが可能です。
fetch('/data-url').then(handleData)
この形式は関数呼び出しのオーバーヘッドを減らすとともに、コード量も削減します。
純粋関数は数学的な関数と同様の特性を持ちます。具体的には以下の 2 つの条件を満たす必要があります。
- 同一の入力に対し、常に同一の結果を返し、計算プロセスで変化がない。
- 外部環境への影響(サイドエフェクト)を持たない。
このような性質を持つとき、式の値は評価順序に関係なく交換可能です。これを「参照透過性」と呼びます。単純な演算式はこの性質を持ちますが、ファイル I/O、現在時刻、乱数など実行時の状態に依存する式は、参照透過性を保持しません。