0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【JavaScript】メソッドチェーンを使用して、可読性向上!

Last updated at Posted at 2022-09-28

概要

先日、ソースレビューにて、メソッドチェーンを使えるようクラスを設計すれば、
可読性向上を狙えるよ、とアドバイスいただきました。
自分メモ用に、整理するためにメモ

アドバイス前...

forEachのループ内部、
"template.find(...")
"template.find(...")
"template.find(...")
...
というように変数"template"に対して複数回、操作を行うような実装を行なっている
まあ、これでも機能実装はできていますが、どこか読み辛さを感じますね。。。
※ 以下のJavaScriptは、【Pug】Pugで編集されたファイルを元に、JQueryで値埋め込みのソースの一部です

$(function() {
    // APiリクエストなどして取得したデータ例
    var list = [
        {
            date:"2022/09/03",
            memo:"",
            name:"枝豆"
        },
        {
            date:"2022/09/03",
            memo:"hogehoge",
            name:"ビール"
        }
    ]

    // データ属性指定で、繰り返すDOMを取得する
    var templateOriginal = $("[data-js-each=table-list-items]")

    // 複製元のDOMを非表示にする(Pugファイルに記載されているのはあくまで”テンプレート”として活用する)
    templateOriginal.hide()

    list.forEach((item, index) => {
        // data属性指定で、複製したDOMを操作する
        var template = templateOriginal.clone().wrap('<div>').parent()
        template.find('[data-js-text=date]').each((_, elem) => {
            $(elem).text(item.date)
        })
        template.find('[data-js-text=name]').each((_, elem) => {
            $(elem).text(item.name)
        })
        template.find('[data-js-text=memo]').each((_, elem) => {
            $(elem).text(item.memo)
        })

        // 操作したDOMを、指定した箇所の最後に追加して、表示する
        template.children().insertAfter("[data-js-each=table-list-items]:last").show()
    
    })
});

アドバイス後!

必要な処理をクラス化して、
"return this"というように、自分自身をreturnすることで、メソッドチェーンができるようになっています
実はこのアプローチは、「fluent interface(流れるようなインタフェース(!))」というもののようです

(!) :
 流れるようなインタフェース
 第3回 Fluent APIとDbContextの機能

きれいですね!
ただ、Fluent Interface(Fluent API)の考え方は、単に、メソッドチェーン使えるようにするので、"return this"しまーす
ではダメで、その設計思想もしっかり理解しないとですね。これは勉強しないと、、、

ともあれ、今回アドバイスもらって、非常に読みやすくなった例を以下に示します


DOM要素にデータを埋め込むためのクラス"dataEmbedder.js"を定義し、そのクラスを
メソッドチェーンでメソッドを呼び出せるようにしています。

dataEmbedder.js
class DataEmbedder {

    constructor(rootElement) {
        this.rootElement = rootElement
    }

    text(target, value) {
        this.rootElement.find(`[data-js-text=${target}]`).each((_, elem) => {
            $(elem).text(value)
        })
        return this // 自分自身を返すことで、呼び出し側でメソッドチェーンで呼び出せるようにする
    }

    each(target, list, doAction) {
        // 複製元のDOMを非表示にする(Pugファイルに記載されているのはあくまで”テンプレート”として活用する)
        const loopElementSelector = `[data-js-each=${target}]`
        const targetElement = $(loopElementSelector)
        targetElement.hide()

        list.forEach((item) => {
            let template = this.rootElement
                .clone()
                .wrap('<div>')
                .parent()

            // コールバック関数を定義する
            // 呼び出し元で、やりたい処理を行う(その際のデータは、"item")
            doAction(new DataEmbedder(template), item) 

            template
                .children()
                .insertAfter("[data-js-each=table-list-items]:last")
                .show()
        })
    }

}

"dataEmbedder.js.each(...)"をご覧ください
「アドバイス前...」と比べてどうでしょうか。かなりスマートになったと思います。
また、"dataEmbedder.js"というクラスに切り出したことで、別のDOM構造をもつものにもデータ埋め込みを行うことが
でき、より汎用的な処理になったと思います。

index.js

index.js
...一部抜粋

$(function() {    
    // APiリクエストなどして取得したデータ例
    var list = [
        {
            date:"2022/09/03",
            memo:"",
            name:"枝豆"
        },
        {
            date:"2022/09/03",
            memo:"hogehoge",
            name:"ビール"
        }
    ]

    const dataEmbedder = new DataEmbedder($("[data-js-each=table-list-items]"))
    dataEmbedder.each(
            "table-list-items",
            list,
            (listItemEmbedder, item) => {
                listItemEmbedder
                    .text("date", item.date) // メソッドチェーンで、データ埋め込みメソッドを呼び出し
                    .text("name", item.name) // メソッドチェーンで、データ埋め込みメソッドを呼び出し
                    .text("memo", item.memo) // メソッドチェーンで、データ埋め込みメソッドを呼び出し 
            }
    )
});

まとめ

今回のアドバイスで、
・ "クラス"のアプローチで共通化を行う
・ メソッドチェーンを使用するために、「fluent interface(流暢な、流れるようなインタフェース)」の考えを持つ
ということを学びました。

またアドバイス受けたら、自分の知識の定着のため、OUTPUTしていきたいと思います!

0
2
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?