Javascriptの関数、メソッド、コールバック、PROMISE等


javascriptを学ぶ上でのつまずきの石

長きに渡る酸いも甘いも経験したプログラマー諸先輩からすれば、どうってことの無いものでも、勉強を始めたばかりの若輩者には大きな躓きの石になるものが多々あり、そういった若輩者でも経験を積んでいくうちに、そういった事も忘れてしまい、何が難しかったのかも分からなくなってしまうことが多い。
そういった事もあり、まだフレッシュなうちに躓いてきた石についてログっておくことは、他に躓いてる人たちのためにもなるかなぁという気持ちで書いてみるのじゃ。

Javascritを学んでいると、なかなかに奇々怪々で理解の難しいトピックが登場する。日常では絶対に使わない用語なので、当然じゃ。

       
  • 関数

  • メソッド

  • コールバック

  • 非同期処理

  • PROMISE, Async, Await


この辺りがなかなか理解が難しいよね。  
まず、以前に書いたけど、日本語がムズすぎる問題。
functionは関数とかいう分かりにくい言葉に訳してるのに、なぜメソッドやコールバックはカタカナなんじゃ!
漢字とカタカナが混在し、言葉からそいつが何者なのかよくイメージできへん。
で、上にリストアップしたトピックは、全部つながっていて、

まず理解すべきは”Object”

Javascritの世界は、すべてオブジェクトで出来ているといっても過言ではない。配列も文字列もJavascritではオブジェクト。

let person = {
  id: 007,  
  firstName: "John",
  lastName: "Doe",
  age: 18,
  hobby: "neru"
};

お馴染みだよね。

関数

数字やデータを色々と処理してアウトプットしてくれるやつ。何か入れると、何かが出てくる不思議な箱。

let x = myFunction(4, 3);

function myFunction(a, b) {
  return a * b;
}
console.log(x); // 12

メソッド

オブジェクトに入った(登録されている)関数をメソッドという。つまり、メソッドは関数。それだけ!

const person = {
  firstName: "John",
  lastName: "Doe",
  hobby: "Neru",
  fullName() {                                      //このfullNameがメソッド。ただ、ここのthisの理解は重要。
    return this.firstName + " " + this.lastName;
  }
};
const name = person.fullName();
console.log(name)  //John Doe

重要なのは、自作する関数以外にJavascriptに元々登録されている関数(つまりメソッド)が沢山あって、例えば、下記コードはドキュメントオブジェクトに元々登録されているquerySelectorっていうメソッドに.exampleという引数を渡して使ってるだけ。こういうオブジェクトとメソッドの関係はいちいち意識したほうが良いと思うよ。

document.querySelector(".example")

コールバック

コールバックは関数に引数として渡される関数 みたいな言い方をよくされてるけど、よくわからんよね。
コールバックの基本は、親関数の中で何らかの処理がなされ、その結果を引数として渡される。で、それを受け取った時点でファンクション発動。
下記が超シンプルなコールバックの形。
numberDisplay の中で、x+y がなされ、それがコールバックの引数にパスされる。で、パスを受け取った瞬間に値をコンソールに表示するっていう関数が実行されている。
値がパスされてから、何らかの仕事をするっていうのが基本形。サッカーをイメージすると分かりやすい。タマが来ないとドリブルもシュートも出来ないからね。
ボールを奪う→ドリブルする→パスを出す→シュートを打つ→裸になる→踊る というファンクションを連続で繰り出しているわけなのじゃ。

const numberDisplay = (x,y,callback)=>{
let sum = x + y;
callback(sum);
}

numberDisplay(1,3,(num)=>{
console.log(num);
})

実際によく使われるパターンが、エラーと成功時のデータの二つを返すタイプ。
下の例では、promptが空の時はエラーメッセージを返し、ちゃんと値が入ってる場合はそのデータを返すというコールバック。
因みに何故コールバックに()を付けないかというと、()をつけた瞬間に(つまり”空であっても”引数を渡した瞬間に)その関数は実行されてしまうからである。
説明したように、何かを処理し、それを引数として受け取った時点でコールバックは初めて実行されないといけないからだ。
イメージとしては、親、子、孫関数があるとして、孫が処理したデータを子に渡し、その子がさらに処理したデータを親に渡すっていうイメージ。
ただ、promise登場以前は、このネスト構造が深くなると、地獄と化していたわけです。

function processUserInput(callback){
var data = prompt('Please enter your name.');
if(!data){
callback('Error!', undefined);
}else{
callback(undefined, data);
}}

processUserInput((error, data)=>{
if(!error===undefined){
console.log(error);
}else{
alert(`Hello ${data}`);
}
})

コールバックヘル

この地獄に嵌った罪深いノビグラマーたちを救うために現れたのが、promiseである。

Promise

Promiseは、いってしまえば、ただのオブジェクト。ただ、地獄の沙汰を救うために、色々なメソッドが用意されたオブジェクトっていう事になる。
この処理が終わったらこれ、で、これが終わったらこれ、もしエラーが帰ってきたらこの処理 っていう感じで、てきぱきと仕切ってくれるのである。

この図でいうと、最初のPromiseの処理で、結果がエラーの時はreject、上手くいった時はfulfillという、いわば合図を送ってくれる。これがPromiseが帰ってくるとかと色んな所で解説してるけども、よくわからん事の本質である。
pendingっていうのは、多少時間がかかる処理であるとイメージして欲しい。この辺りが非同期処理の理解にかかわってくるのじゃ。
で、成功の合図があった暁にはPromiseオブジェクトにあらかじめ入ってる.thenメソッドにて登録された関数を順番に実行してくれる。
地獄のネストからの生還である。
下にw3schoolからのサンプルコードを載せておく。

let myPromise = new Promise(function(resolve, reject) {
  let x = 0;

// 何らかのコード (try to change x to 5)

  if (x == 0) {
    resolve("OK");
  } else {
    reject("Error!");
  }
});

myPromise.then((resolve)=>{
document.getElementById("demo").innerHTML = resolve;  //OK(xが0の場合)
}).catch((reject)=>{
document.getElementById("demo").innerHTML = reject;  //Error!(xが0以外の場合)
})

見てみると、コールバックで解説したように、エラー時と成功時に別の引数を次の関数に渡しているのが分かるじゃろう。
解説しようと思っとったが、バイトの時間なので詳細はまた次の機会じゃ。
w3schoolはシンプルで分かり易いので、リファレンスにおすすめじゃ。
w3school
じゃあの。

【追記】Promise/Async/Awaitについてもう少し深く考えたぞ。