◆ プロトタイプ拡張するのでボツ

メソッドチェーンで使うライブラリだと if 文みたいに条件に応じてチェーンしたりしなかったりしたいことがよくあります

return something()
.method1("foo", value1) // if (value1 != null) のときだけしたい
.method2("bar", value2) // if (value2 != null) のときだけしたい
.method3()

素直にやろうとすると if 文で分岐ですが チェーンが途切れて見やすくありません

let chain = something()
if (value1 != null) chain = chain.method1("foo", value1)
if (value2 != null) chain = chain.method2("bar", value2)
return chain.method3()

ということでこういうメソッドを用意します

Object.prototype.chainWhen = function(condition, fn) { return condition ? fn(this) : this }

使用例

class C {
method1(v1, v2) {
this.x1 = [v1, v2]
return this
}

method2(v1, v2) {
this.x2 = [v1, v2]
return this
}

method3(v1, v2) {
this.x3 = [v1, v2]
return this
}
}

let value1 = null
let value2 = 10
new C()
.chainWhen(value1, c => c.method1("foo", value1))
.chainWhen(value2, c => c.method2("bar", value2))
.method3()
// C {x2: Array(2)["bar", 10], x3: Array(2)[undefined, undefined]}

メソッドチェーンライブラリの代表的なものと言えば jQuery ということで jQuery で使った例

<!doctype html>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>

<label><input type="checkbox" id="animation" checked> animate</label>
<div>
<button>1</button>
<button>9</button>
<button>32</button>
</div>

<style>
button { position: relative; }
button, label { user-select: none; }
</style>

<script>
Object.defineProperty(Object.prototype, "chainWhen", { enumerable: false, value: function(condition, fn) { return condition ? fn(this) : this }})

$("button").on("click", eve => {
const anim = animation.checked
$(eve.target)
.chainWhen(anim, c =>
c.animate({top: "5px"}, 50)
.animate({top: "-5px"}, 50)
.animate({top: "0"}, 50)
)
.text((i, text) => ~~text + 1)
})
</script>

DEMO

チェックがついてるときだけボタンクリック時にアニメーションします


便利ですね
……まぁこれボツ機能なんですけど
プロトタイプ拡張する上に Object の拡張なので 影響が多いのですよね
プロトタイプ拡張は避けたいのに他の方法だと外側から関数で包む必要があって見やすさが落ちますし この手の機能は作ってはプロトタイプ拡張がネックになって結局使わずじまいです