JavaScriptのコールバック関数について

JavaScript第一号の記事です。
JavaScriptを飛ばしてJSONの記事はあります。

こんな動きを実装しました!と堂々と記事にする以前の段階なので、そうなれるようにがんばります。

下積み記事第一弾はコールバック関数です。
やりたいことがあっても、うまくいかないときは大体コールバック関数に阻まれていることが多いです。
お勉強できる教材がないか探しました。

エンジニアYouTuberがすごい

YouTubeでプログラミングの学習ができます。
動画なので感覚的にはドットインストールみたいです。
加えて、教えてくださる方が映っています。

私が見たのは
しまぶーのIT大学
【基礎から学ぶ JavaScript 入門 #1】フロントエンド開発でJavaScriptが必要な理由を解説!【ヤフー出身エンジニアが教える初心者向けプログラミング講座】
です。

とてもわかりやすかったです!これが無料!

動画内でも「コールバック関数は初心者がつまづきやすいところ」と言われており、コメント欄を見ると、同じくコールバック関数と戦う方たちの声がたくさん。 励みになります。

このしまぶーさんという方以外にもたくさんの方がプログラミング関係の動画を上げてくださっているのですね。
結局、有用な記事を探し出して読むのと同じなので、自分に合ったYouTuberを探してみるのもいいなと思いました。

『たった3分でプログラミングを学習できる!?』知らないと損をする教育系Youtuber3選!【在宅ワークの方必見】 | キカガク公式ブログ

関数いろいろ

まずはいろいろある関数を挙げます。

関数宣言と関数式

どちらも関数の宣言をする文法です。

関数宣言

function hello() {
  console.log('こんにちは');
}

関数式

let hello = function() {
  console.log('こんにちは');
};

名前のない関数、匿名関数を変数helloに入れています。 function() {} 部分は関数リテラルという「値」で変数に代入しているため、後ろに ; を付けます。
(文末の ;javascriptで自動挿入されるそうなのでなくても大丈夫ですが、「入れるもの」だということは抑えておきたいです)

これら書き方が2つあって混乱します。「文字列の扱い ""'' 」のようにどちらを使えばいいのか...!

関数式と関数宣言の違いについて:
関数式

基本は関数の呼び出しの前後どちらに書いてもOKな関数宣言を使って、スコープを意識するときは関数式の方がいいのかなと思いました。

アロー関数

さらに関数リテラルをアロー関数を使ってシンプルに書くこともできます。

let hello = () => { 
  console.log('こんにちは');
};

// 処理が一文のときは {} を省略できる
let hello = () => console.log('こんにちは');

// 引数が一つのときは()を省略できる
let hello = name => console.log('こんにちは' + name);

アロー関数の基本

アロー関数と普通の書き方では何が違うかというと、this の解釈だそうです。

【JavaScript】アロー関数式を学ぶついでにthisも復習する話 - Qiita

アロー関数、目がまだ慣れません...!

即時関数

関数を定義すると同時に実行される関数です。

(function () {
    //処理
}());

JavaScriptで即時関数を使う理由 - Qiita

即時関数を使う理由は、スコープの汚染を防ぐため。
もっと積極的に使っていかなくてはならない関数であることは分かりました。
おいおい復習したいです。

高階関数

引数が関数(=コールバック関数)の関数。高階関数の中で関数を実行します。

function 高階関数名(コールバック関数) {
  // 処理
  コールバック関数();
}

☆「高階関数名」はなくても、匿名関数でもOKです。

匿名関数、無名関数

名前がなくても関数として動かすことができる関数。
function(){} という、今までさんざん出てきたやつです。

コールバック関数

ここでようやくコールバック関数についてです。
「引数として渡されている関数」のことをいいます。

コールバック関数を使った文法

引数になっている関数なんだ、ということを落ち着いて考えればコードも読めそうです。

言葉にすると、コールバック関数の書き方は

  • あらかじめ宣言した名前のある関数を入れるのか
  • 匿名関数をそのまま入れるのか

です。

コールバック関数をあらかじめ宣言しておく場合

// 高階関数
function kokai(fn)  {
  // 処理
  fn();  // コールバック関数の処理←よく「fn」と書かれる。
}

// コールバック関数になる関数の定義
function callback1(param) {
  // 処理
}
function callback2(param) {
  // 処理
}

// 高階関数(kokai())の実行
kokai(callback1);

コールバック関数に引数を渡す場合

高階関数の引数にコールバック関数の引数を定義します。
引数の順番は決まっていなさそうです。

function kokai(fn, param)  {
  // 処理
  fn(param);  // コールバック関数の処理
}

kokai(callback2, コールバック関数の引数);

コールバック関数が匿名関数の場合

関数式の変数部分を入れるのと、代入部分である匿名関数を入れるのは同じ、と考えれば納得です。

// 高階関数
function kokai(fn)  {
  // 処理
  fn(); 
}

// コールバック関数になる関数の宣言(関数式)
let callback3 = function(param) {
  // 処理
}

// 高階関数(kokai())の実行
kokai(callback3);  // コールバック関数が変数

kokai(function(param) {    // コールバック関数が匿名関数
  // 処理
});

これはよく見掛けます。
1回限りしか使わないコールバック関数なら、わざわざ関数宣言しなくてもまるごと引数に入れてしまおうということです。

コールバック関数に引数を渡す

高階関数の処理内容を、引数であるコールバック関数の引数として渡す場合です。

 // 高階関数の宣言
function kokai(fn) {
  const input = 'hoge';
   fn(input);    // コールバック関数に引数を渡す、という定義
}

// 高階関数の実行
kokai(function(input) {
  // inputを使った処理
});

アロー関数の高階関数

ぎりぎり分かりそうなコードです。

// 通常
const calc = function(x, y, fn) {
  return fn(x, y);
};
 
console.log(calc(2, 4, function(a, b) {
 return  a + b;
}));  // 6
console.log(calc(2, 4, function(a, b) {
  return a * b;
}));  // 8


// アロー関数
calc = (x, y, cb) => {
  return cb(x, y)
}

console.log(calc(2, 4, (a, b) => a + b))  // 6
console.log(calc(2, 4, (a, b) => a * b))  // 8

アロー関数では、(a, b) => a + b 部分がコールバック関数です。匿名関数です。
そしてアロー関数では return が省略できます。
とても短く書けます。

アロー関数については今深入りすると大混乱なので、このへんにします。

まだまだ奥が深い

関数の種類も、他に純粋関数再帰関数、あと分からない単語ではクロージャカリー化などがありました。

まずはコールバック関数を意識しながらコードを見て目を慣らします!

それにしても具体的でないコードはこうも分かりにくいのか、と思いました。 (動画のコードまんま書くのはは良くないと思い...。)
オリジナルないい例が思いついたら直したいです。

おしまい。