質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

5回答

680閲覧

関数型でプロパティを作りたい

dada-sygnas

総合スコア34

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2022/12/14 03:26

関数型で内部のプリミティブな変数をプロパティとして取り出したい

関数型オブジェクトの内部変数を、getter のように () を付けずに取り出したいと考えています。
get アクセサを使えば良いのですが、もっと簡潔な方法はないかと考えています。

js

1obj.hoge(); // ではなく 2obj.hoge; // という感じ

失敗する例

カウンターを例に作成しました。
下記の例では counter.add() を実行しても counter.count が更新されることはありません。
count はプリミティブな変数なので useCounter() 実行時の値が固定されているためです。

js

1const useCounter = (num) => { 2 let count = num; 3 4 const add = () => { 5 count += 1; 6 }; 7 8 return {add, count}; 9}; 10 11const counter = useCounter(0); 12 13counter.add() 14console.log(counter.count); // 0 15counter.add() 16console.log(counter.count); // 0

関数で取り出す

関数を作って取り出せばもちろん問題ありません。

js

1const useCounter = (num) => { 2 let $_count = num; 3 4 const add = () => { 5 $_count += 1; 6 }; 7 const getCount = () => { 8 return $_count; 9 }; 10 11 return {add, getCount}; 12}; 13 14const counter = useCounter(0); 15 16counter.add() 17console.log(counter.getCount()); // 1

getter を使う

useCount() が返すのはオブジェクトなので get アクセサを使いました。
これは希望通りの結果になります。
しかし変数が増えると get xxx(){} も増えるのが難点です(これは一つ前の例でも同様です)。

js

1const useCounter = (num) => { 2 let $_count = num; 3 4 const add = () => { 5 $_count += 1; 6 }; 7 8 return { 9 add, 10 get count(){ return $_count; } 11 }; 12}; 13 14const counter = useCounter(0); 15 16counter.add() 17console.log(counter.count) // 1;

何か良い方法は無いでしょうか?

Class にすればいいのではと言われればその通りですが、今回は関数型にこだわってみました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2022/12/14 05:38

> 今回は関数型にこだわってみました。 何かこだわらなければならない背景はある状況でしょうか?
dameo

2022/12/14 06:19

アロー関数ってthisが使えないんですよね。
dada-sygnas

2022/12/14 09:53

>maisumakun 様 既存の class をリファクタリングしている時に ・private なメソッド、プロパティを明確にしたい ・this書くの面倒くさい という理由から関数型にしました。
dameo

2022/12/14 10:19

関数型という表現は良くないですね。 関数=functionだとthisが使えるので意図が180度違う形で伝わってしまっています。
dada-sygnas

2022/12/14 10:24

>dameo 様 ご指摘ありがとうございます。確かにその通りですね。 名称を知らないのですが、なんと表現すればいいでしょうか?
dameo

2022/12/14 10:29 編集

function禁止でアロー関数のみとするか、thisを使用しない!を条件に入れればいいと思いますよ。
maisumakun

2022/12/14 11:48

> private なメソッド、プロパティを明確にしたい 今のclassにはprivate機能があります。
guest

回答5

0

以下はどうでしょう?

javascript

1const useCounter = (num) => ({ 2 count: num, 3 add() { this.count++; } 4}); 5 6 7const counter = useCounter(10); 8 9console.log(counter.count); // 10 10 11counter.add(); 12console.log(counter.count); // 11 13 14counter.add(); 15console.log(counter.count); // 12 16

投稿2022/12/14 06:09

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dada-sygnas

2022/12/14 09:36

ありがとうございます。 なるほど!最初からオブジェクトにしてしまう方法ですね。 private扱いにしたい変数・関数があると使えませんが、今回の例だとアリですね。
guest

0

普通にclass処理案件だと思いますが、関数でやるというのはこういうことでしょうか?
(以下ソースはだめな例でした)

javascript

1function useCounter(num){ 2 this.count = num; 3 this.add = () => { 4 this.count++; 5 }; 6 return this; 7}; 8 9const counter = useCounter(0); 10counter.add() 11console.log(counter.count); // 1 12counter.add() 13console.log(counter.count); // 2

※上記、よく考えたらnewしてないのでthisがwindowですね
結局newするならクラス処理と同等でした

javascript

1function useCounter(num){ 2 this.count = num; 3 this.add = () => { 4 this.count++; 5 }; 6 return this; 7}; 8 9const counter = new useCounter(0); 10counter.add() 11console.log(counter.count); // 1 12counter.add() 13console.log(counter.count); // 2

投稿2022/12/14 04:08

編集2022/12/14 04:26
yambejp

総合スコア114581

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dada-sygnas

2022/12/14 09:46 編集

ありがとうございます。 ES5の時代は class が存在しなくて function を new して代用してましたね。
guest

0

最初のコードで、add() を以下のように変更すればよいでしょう。

js

1 const add = function() { 2 this.count += 1; 3 }

投稿2022/12/14 03:39

int32_t

総合スコア20670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dada-sygnas

2022/12/14 09:37

ありがとうございます。 最初のコードというと「失敗する例」でしょうか? そこだけ変更だと NaN になるかと。
guest

0

add関数からクロージャを使って関数スコープのcount変数を参照したい。
かつ、count変数を公開したい。
ならば、こんな感じでしょうか?

javascript

1const useCounter = (num) => { 2 let result = {}; 3 4 result.count = num; 5 6 result.add = () => { 7 result.count += 1; 8 }; 9 10 return result; 11}; 12 13 14const counter = useCounter(0); 15 16counter.add() 17console.log(counter.count); // 1 18counter.add() 19console.log(counter.count); // 2

投稿2022/12/14 13:47

ku__ra__ge

総合スコア4524

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dada-sygnas

2022/12/15 09:36

ありがとうございます。 なるほど、public にしたいものだけ result に格納すれば private と完全に切り分けることも出来ますね。 class の this に近いけど this のような「今は何がthis?」が無いのもいいですね。
guest

0

ベストアンサー

参照渡しが出来るようなstateを生成する関数を定義するのはどうでしょう?

js

1const useRef = (value) => { 2 return {current: value}; 3}; 4 5const useCounter = (num) => { 6 let count = useRef(num); 7 8 const add = () => { 9 count.current += 1; 10 }; 11 12 return {add, count}; 13}; 14 15const counter = useCounter(0); 16 17counter.add() 18console.log(counter.count.current); // 1 19counter.add() 20console.log(counter.count.current); // 2

投稿2022/12/14 04:10

Karibash

総合スコア54

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dada-sygnas

2022/12/14 09:41

ありがとうございます。 実はこの質問のきっかけは Vue3 の Composableなモジュール使っている時にピュアJSでも似たようなことができないかというのが発端でした。 Vue3 では ref() を使っているのでまさにその発想ですね。
Karibash

2022/12/14 10:10

関数型でやりたいとの事だったので、このパターンがベストなのかなと思います。 thisを使うパターンはもはや関数型では無いと思いますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問