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

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

ただいまの
回答率

90.33%

  • JavaScript

    17542questions

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

  • 関数

    228questions

    関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

  • Babel

    60questions

    Babelは、JavaScriptの次世代仕様であるECMAScriptのコンパイラ。次世代の標準機能を用いて記述されたコードを、それらの機能に対応していないブラウザでも動作するコードに変換することができます。

javascriptのreduceの戻り値を関数にしたときの処理の流れがわかりません。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 639

u310ai

score 2

javascriptで関数の配列をreduceで回し、reduceの戻り値を関数にして、
その関数の中で処理をしてから戻すといった関数を作ったのですが、処理の流れが思ったと通りではありませんでした。

コードは以下です。

const a = () => 'a'
const b = () => 'b'
const c = () => 'c'
const d = () => 'd'

const array = [ a, b, c, d ]

function func(args) {
  return args.reduce((accum, current, index) => {
    console.log('=====outer===== index: ' + index + ', accum: ' + accum() + ', current: ' + current())
    return (str='*') => {
      console.log('---inner--- index: ' + index + ', accum: ' + accum() + ', current: ' + current())
      return str + accum() + ':' + current()
    }
  })
}

console.log(func(array)('結果: '))

結果は以下です。

=====outer===== index: 1, accum: a, current: b
---inner--- index: 1, accum: a, current: b
=====outer===== index: 2, accum: *a:b, current: c
---inner--- index: 1, accum: a, current: b
---inner--- index: 2, accum: *a:b, current: c
---inner--- index: 1, accum: a, current: b
=====outer===== index: 3, accum: **a:b:c, current: d
---inner--- index: 1, accum: a, current: b
---inner--- index: 2, accum: *a:b, current: c
---inner--- index: 1, accum: a, current: b
---inner--- index: 3, accum: **a:b:c, current: d
---inner--- index: 1, accum: a, current: b
---inner--- index: 2, accum: *a:b, current: c
---inner--- index: 1, accum: a, current: b
結果: **a:b:c:d


この結果で理解できないのは、
全体的にどのような処理の流れなのかがわかっていないのですが、
特にreduceの戻り値である関数(inner)の処理が何回もされているのと、
func関数の戻り値の関数を呼び出す際に指定した、引数('結果: ')が最後で適用され、それまではundefinedだということです。
こういったコードを説明している日本語のサイトなどがありましたらそちらを載せていただくだけでもありがたいです。

reduxのcomposeの定義を見ている際に理解できないコードがあったので、似ているコードを作って理解しようと思ったらはまってしまいました。

よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

関数とreduceで実行されることをばらすと、下記のような動作になっています。

const a = () => 'a'
const b = () => 'b'
const c = () => 'c'
const d = () => 'd'

// 初期値指定がないため最初のaccumは最初の要素になり、indexは1から始まる。
const accum1 = a;
const current1 = b;
const index1 = 1;
console.log('=====outer===== index: ' + index1 + ', accum: ' + accum1() + ', current: ' + current1());
const accum2 = (str='*') => {
  console.log('---inner--- index: ' + index1 + ', accum: ' + accum1() + ', current: ' + current1());
  return str + accum1() + ':' + current1();
};
const current2 = c;
const index2 = 2;
console.log('=====outer===== index: ' + index2 + ', accum: ' + accum2() + ', current: ' + current2());
const accum3 = (str='*') => {
  console.log('---inner--- index: ' + index2 + ', accum: ' + accum2() + ', current: ' + current2());
  return str + accum2() + ':' + current2();
};
const current3 = d;
const index3 = 3;
console.log('=====outer===== index: ' + index3 + ', accum: ' + accum3() + ', current: ' + current3());
const accum4 = (str='*') => {
  console.log('---inner--- index: ' + index3 + ', accum: ' + accum3() + ', current: ' + current3());
  return str + accum3() + ':' + current3();
};
console.log(accum4('結果: '));

最初のaccumが単なるaにのはいいとして、問題は次のaccumですが、returnで渡した関数そのものになります。そして、次の処理のouterの所でそのaccumが呼ばれるため、returnで渡した関数の中身が実行されます。上のコードで言うと、accum2がouterで実行されているという所ですね。そのような流れで、どんどんaccumには過去の関数も蓄積され、その度にouterでもよばれているので、何度もinnerが表示されると言うことです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/06 08:50

    処理の流れが大変わかりやすく、またどう考えればいいのか勉強になりました!
    有難うございました!

    キャンセル

0

javascriptで関数の配列をreduceで回し、reduceの戻り値を関数にして、
その関数の中で処理をしてから戻すといった関数を作ったのですが、
(中略)
reduxのcomposeの定義を見ている際に理解できないコードがあったので、似ているコードを作って理解しようと思ったらはまってしまいました。

reduxcompose関数を使ったことがないのですが、冒頭の一文や、composeという言葉から推測するに、やりたいことは質問文に掲載されているようなAではなく、Bではないでしょうか?

// A: 質問文のコードからreducerを取り除いて簡略したもの
const func = f => g => v => v + f() + g();

ではなく、

// B:
const compose2 = f => g => v => f(g(v));
//とか
const compose3 = f => g => h => v => h(f(g(v)));

その上で、Arrayreduceメソッドを使って、複数の関数をcomposeできる便利なユーティリティー関数を作りたいみたいな話が根本的なところにあるのかなと思いました。

これを前提に簡単なデモコードを書いてみました。

// compose関数に渡す関数(curry化は省略)
const trim = str => str.trim();
const splitBy = splitter => words => words.split(splitter);
const joinWith = jointer => arr => arr.join(jointer);
const toLowerCase = str => str.toLowerCase();

const Identity = value => value;

const compose = (...funcs) => {
    return funcs.reduceRight((chainedFunc, currentFunc) => {
            return (...args) => currentFunc(chainedFunc(...args))
        }, Identity)
}

// 左右の空白除去してハイフン区切りのスラグを作成する関数をcompose
const slugify = compose(toLowerCase, joinWith('-'), splitBy(' '), trim)
console.log(slugify('  My First Blog Entry  ')); // "my-first-blog-entry"

※ 一般的にcomposeというと、引数に渡された関数を右端の関数から順に適用していく場合が多いと思うので、reduceRightを使いました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/06 09:06

    確かに僕が見たサイトのcomposeの説明でもreduceRightを使っていたのですが、
    元のコードを見るとreduceを使っておりましたので、これはどういうことかと思い調べていて今回の質問に至りました。
    以下が元のコードの該当の部分です。

    `return funcs.reduce((a, b) => (...args) => a(b(...args)))`

    調べる中でもっとわかりやすくしようと思い、
    質問文のようなコードに変えてテストしていました。
    これから上記のコードを紐解いていくにあたって、回答していただいたコードは助けになりそうです。
    有難うございました!

    キャンセル

  • 2018/07/06 17:09

    どういたしまして!頑張ってください!

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    17542questions

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

  • 関数

    228questions

    関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

  • Babel

    60questions

    Babelは、JavaScriptの次世代仕様であるECMAScriptのコンパイラ。次世代の標準機能を用いて記述されたコードを、それらの機能に対応していないブラウザでも動作するコードに変換することができます。