◆ プロパティもイミュータブルにする?
◆ 状態は引数として受け取るようにすると関数型っぽさが増す
◆ 難しくなるとも言える

const は当たり前のように使ってる

ES2015 からの const は常用してます
すでに変数使ってるのに気づかず同じ名前使ってしまうミスとかが減りますし なにより読むときに助かります
状態を知りたい変数があったときに スコープ内で 「const XXX =」 という部分を探すだけなのですごく楽です
直後に if 文で変更するだけでも let 使ってしまうと その後 if 文以降でも書き換えできるのでちゃんと読む必要が出てきます
なので 直後の if 文で変えるだけでも const にして 即時関数の返り値を入れたいなって思うくらい
とは言っても関数実行するのもなぁって気持ちもあるので do 式早くきて!って感じです

プロパティは普通に書き換えてる

というわけでイミュータブルを積極的に使ってると思ってたのですが考えてみるとプロパティはそうでもないです
気軽に状態を変更していきますし むしろ const にするために 「const values = {...}」 みたいなオブジェクトをつくることもあったりするくらいです
オブジェクトのプロパティまでイミュータブルって使いづらくなりますし 一度渡した参照をもたせたままで値が変わってくれることを利用したコードも多いので 不便さが勝ってきます
単純にパフォーマンス的にもコストが高くなるのも気になります

状態持ってるものをイミュータブルにしてみる

通常の変数を const に置き換えるのは もともと変数はあまり再代入せず 書き換えるのはプロパティということが多かったのでスムーズに移行できましたがプロパティまでは大変な上にメリットよりデメリットが多い気がします
状態を持ちたいものの例でページャを作ってみます

状態をもつ場合

まずは普通に状態を持つものです
page プロパティに今のページを保存して goNext で次のページに移動して goPrevious で前のページに移動します
getContent で今のページのデータを取得します
状態があるのがオブジェクト指向ぽいのでよくある感じのクラス構文にしてます
また 変な入力とか範囲とか面倒な部分は省略してます

class Pager {
constructor(arr, page_num) {
this.arr = arr
this.page_num = page_num
this.page = 0
}

goNext() {
this.page++
}

goPrevious() {
this.page--
}

getContent() {
return this.arr.slice(this.page * this.page_num, (this.page + 1) * this.page_num)
}
}

毎秒次のページを console.log する例です

const pager = new Pager([...Array(100).keys()], 15)
const showLoop = () => {
console.log(pager.getContent())
pager.goNext()
setTimeout(showLoop, 1000)
}
showLoop()

ページ状態は pager の中に収まってるので pager に対して命令を送るだけで扱いやすいです

状態を持たない場合

これで pager に更新できる状態を持たないとすると

class Pager {
constructor(arr, page_num) {
this.arr = arr
this.page_num = page_num
}

getContent(page) {
return this.arr.slice(page * this.page_num, (page + 1) * this.page_num)
}
}

状態が変わる「今のページ番号」は持たないので goNext や goPrevious はなくなりました
getContent に page を引数で受け取って page に対応するものを返します
変わるものは外部から渡されるようになりました

メソッドが getContent しかないですし こういうのだと class より関数のほうが見た目的に好みです
this 書かなくて済みますし

const createPager = (arr, page_num) => page => arr.slice(page * page_num, (page + 1) * page_num)

これで毎秒次のページを表示します

const getContent = createPager([...Array(100).keys()], 15)
const showLoop = page => {
console.log(getContent(page))
setTimeout(showLoop, 1000, page + 1)
}
showLoop(0)

なんか関数型の言語に近いものを感じますね
イミュータブル自体そっちから取り入れたものなのでそうなるのが正しい気もしますけど

どっちがいいのかな

最初はページャの状態なので ページャがページ番号を持ってましたが 今はページャを作るとインスタンス (オブジェクト) すらなく関数が返ってくるだけです
それぞれが状態を持たずに引数でページを入れたらそのページの部分が返ってくるのはシンプルといえばそうですが ページャというものがあってその中に情報が入っててくれたほうがわかりやすいような気もします
外部でページャインスタンスを持つか ページ番号を持つかの違いなだけかもですが 関数型風な考え方ってなれないと分かりづらいですし 多少なれても複雑になると難しいです

そういう作りになれてる人ならいいですが JavaScript で主に扱う代表的なものの DOM がオブジェクト指向らしく状態を持つようなものですし JavaScript そこまでする必要もあるのかなーってところです