LoginSignup
430

フルスタックプログラマーの卵どもにおくる、独学チートシート : 2

Last updated at Posted at 2023-11-03

卵どもに贈る独学チートシートの続き

前回記事を勢いよく書き出したのは良いものの、途中で書くことが多すぎて挫折、後半部分はサマリーのみで逃亡したわけですが、今いるマニラは長期連休で暇やなあと思っていた時に、あれを書き切ってしまわんといかんと思って戻ってきました。
正直Qiitaなどに駄文を書いたところで何の儲けにもならず、下手を打てば100戦錬磨のプログラマー諸先輩方からの厳しいツッコミに晒されて蜂の巣にされるわけで、リスクしかないわけですが、前回かなりのいいねやストックをしていただいていた方々がおり、続きを書かねばならぬという気持ちになりました。卵のみんな、ありがとな。
では、続きのJavaScriptから。

JavaScript

  • JavaScriptの大部分はオブジェクトで出来ている
  • APIの理解とJSONの処理
  • Promise, async/awaitの理解
  • ファンクションはいつ動くのか、同期、非同期処理の理解

前回書いたHTMLやCSSはマークアップ言語であって、プログラミング言語ではない。なぜなら、データの処理はしていないからである。書いたように、文章構造の定義と、装飾である。
で、色々なデータを料理する言語として、JavaScriptである。
ウェブ開発をしていると、おそらく、ここで躓く卵どもが多いと思う。わしも、20年前にウェブをやっていたときは、正規表現やコールバックヘルなどに巻き込まれ、ここで挫折した。
JavaScriptが何やってるかというと、何かをどうにかしてくれるのである。
どうの部分を絶えず意識していれば、全く難しくない。
自分探しと同じで、自分が何をどうしたいのか が分かっている事が一番重要で、JavaScriptは所詮、貴様のやりたい事をやってくれる道具であって、それ以上ではない。
で、の部分には、

  • 文字列
  • 数字
  • ブーリアン(true or false)
  • undefined
  • null (何も存在しない)

のどれかが入る。

IMG_5982.JPG

定義型だとかなんとか言われてるけど、結局はこれだけで、もっと整理されたデータやまとまったのデータを扱いたい場合は、ArrayかObjectに上記の値を突っ込んでおけばよい。
objectはシンプルに{key:value}というラベルと値のセットであり、arrayは値だけがズラッと入ってるイメージである。
どうしたいかの部分は、関数/Function と言われている部分で、まさにファンクション(機能)である。
基本の型は超シンプルで、

keyword 名前 (材料) {
  材料  何かする
}

statement (この時) {
  これをする
}

これだけである。
具体的には、

function printName(name) {
  console.log(`Hello ${name}`);
}

//もしくはアローファンクションなら
const printName = (name) =>{
  console.log(`Hello ${name}`);
}
// if statement なら
const name = "Goku"

  if (name === "Goku") {
    console.log(`Ossu! ${name}`)
  } else {
    console.log(`Genkidesuka? ${name}`)
 }

// for statement なら
for (let i=0; i<=5; i++) {
   console.log('Ossu!');
}
 

で、functionとif statementなんかを組み合わせて、さらにクラスを定義して犬小屋を作るとしたら、

// 犬小屋クラスを定義
class DogHouse {
  constructor(color, size) {
    this.color = color;
    this.size = size;
  }

  // 犬小屋を建てるメソッド
  build(budgetIsEnough) {
    return new Promise((resolve, reject) => {
      if(budgetIsEnough){
      resolve(`${this.color}色の${this.size}サイズの犬小屋がでけた!`);
      } else {
      reject("予算不足です");
      }
    });
  }
}

// 犬小屋を建てるファンクションを定義
const buildDogHouse = (color, size, budget) => {
  const myDogHouse = new DogHouse(color, size);
  return myDogHouse.build(budget);
}

// 犬小屋を建てるファンクションをトリガー
const dogHouse = buildDogHouse('', '大きい', true)
console.log(dogHouse); // 金色の大きいサイズの犬小屋がでけた!

みたいなノリである。
color,size,budget などの、何を とbuild(),buidDgoHouse()の どうする で出来ている。クラスとオブジェクトに関しては、下記で説明しておく。
JavaScriptを書くときは、常に何をどうしたいのか を日本語で考えておく事。
例えば、"user objectが入ったarray" を "mapでループし" て <div className="userList> の中 に "名前とID"  を "表示する" みたいな感じ。
日本語(何であれ人間語)で書けるものは、ほとんどをコードに出来る。出来ないのは、あなたの言葉が破綻しているのだ。
コードを書くコツとしては、まずコメントで、何をしたいか書き出し、具体的なコードはGoogle先生か、ChatGPT教授にでも聞けば助けてくれる。
ChatGPTなどはコードの生成もしてくれるが、お前自身が何をしたいかよく分からなかったり、聞きたい事が正確でないと、返ってくるコードも間違ったコードしか返ってこない。
例えば、下記は先ほど書いていたコードなんだけど、ユーザーがサインインして新しいuser documentがデーターベースに作られたら、そのdocument内のrefCodeの値をゲットして、それとマッチするドキュメントを探し、そのドキュメントのUIDをサインインしたユーザーのドキュメントに保存みたいな処理。
全体見ると、結構複雑なんだけど、1工程づつ書き出していけば、自分でやりたい事が理解しやすい。で、ここに実際のコードを埋めていけば良い。
ちなみにこれは、いわゆるネズミ講みたいに、サインインしたユーザーと、そのユーザーを紹介したユーザーを結び付ける処理。

// Step 1: When the new user document created, fetch document

// Step 2: get refCode in user document

// Step 3: Find the matched document by refCode

// Step 4: Find the uid from the matched document
   
// Step 5: Save the referer's UID to the created user's document

で、コードを埋めていくとこんな感じになる。長めのコードでも、1行づつ解決していくと、それほど難しくない。

// Step 1: When the new user document created, fetch document
 exports.updateReferenceOnUserCreation = functions.firestore.document("users/{userId}").onCreate(async (snap, context) => {
  const userDoc = snap.data();
  
    if (!userDoc) {
    console.log("No Documents Found");
    return null;
  }

// Step 2: get refCode in user document
  const userRefCode = userDoc.referenceCode.refCode;
  const userMyRefCode = userDoc.referenceCode.myRefCode;

    if (!userRefCode) {
    console.log("No reference code found for the user");
    return null;
  }

// Step 3: Find the matched document by refCode
  const querySnapshot = await db.collection("users").where("referenceCode.myRefCode", "==", userRefCode).get();

// Step 4: Find the UID from the matched document
  let matchedRefID;
  if (querySnapshot.empty) {
    matchedRefID = process.env.OWNER_UID;
  } else {
    const matchedDoc = querySnapshot.docs[0];
    matchedRefID = matchedDoc.data().uid;
  }
   
// Step 5: Save the referer's UID to the created user's document
  await snap.ref.update({
    "referenceCode.referer": matchedRefID,
  });

JavaScriptの大部分はオブジェクトで出来ている

で、上でも書いたように、JavaScriptはデータを色々と処理してくれる。
例えば、ユーザーが書いたQiitaの記事のデータを、サーバーに送る、サーバーから返ってきたデータを、加工して表示するとか。そのほか色々お前ら次第。
で、そのデータっていうのは、上に書いた、テキスト、数字、ブーリアン値、null値の4種類であり、例えばフォームなら、名前、メール、住所、電話番号とか、一個一個処理してられないよね。なので、ObjectとかArrayにまとめてパッケージングしておけば扱いやすい。
APIを介したデータの送受信、各種のライブラリ、JavaScriptそのものや、前回説明したHTMLのDOMに至るまで、ほぼ全てがオブジェクトという形でパッケージされていると言っても過言ではなく、HTTPを使ったサーバーとフロントとのやり取りも、JSONというオブジェクトである。
JSONは、サーバーとのやりとりは文字列データしか使えないため、JavaScriptのオブジェクトを文字列変換したものに過ぎない。
なので、JavaScriptを理解しようと思えば、Objectを常に意識するのが、理解の近道だ。
オブジェクトについては、以前記事に書いたので、これを読んで欲しい。

APIの理解とJSONの処理

こちらにもAPIについて書いたけど、ウェブ上のサービスの根幹がAPIで成り立っている。
すごく簡単なイメージとしては、ウーバーイーツである。
住所(URI)と注文(Request body)を送れば(HTTP Request)、レストランのキッチン(サーバー)が注文を作り、それをドライバーが受け取って送り返してくれる(HTTP Response) 。あとは、食うだけである。
やってることは、注文をだすのと、受け取りである。
料理はレストランのシェフが勝手に作ってくれるし、自分はレシピや材料を知る必要がない。
で、その注文と受け取った飯というのは、先に書いたJSON、つまりオブジェクトの形になって送受信される。
サーバーサイドのプログラムとは、このキッチンのオペレーションを作る事である。
例えば、ここのエンドポイントにアクセスすると、ダミーのブログ記事のデータがJSONで返ってくるのが見れる。
https://jsonplaceholder.typicode.com/posts
で、この返ってきたJSONデーターを、フロント側のHTMLに流し込めば、ブログページの出来上がりである。
https://jsonplaceholder.typicode.com が住所、 /posts が注文の部分である。

APIからデータを取得するような処理は、下に書く非同期処理に大きく関係してくる。 サーバーやデーターベースを介する処理は時間がかかるからである。つまり、下の例えでいうと、飯を炊くのと同じであり、データーをリクエストして待っている間に、他の処理を色々と出来た方が良いよねという事である。

同期、非同期処理とPromise

同期、非同期の理解は超重要で、超簡単である。
なぜなら、わしらは普段普通にやっているからだ。
元々のJavaScriptは、同期処理と言って、上のコードから順番にコード処理していっておった。
で、これではあかんとなったわけだ。
晩飯に豚汁、チャーハン、焼きサバを作る所をイメージしてみて欲しい。
まず、飯を炊く。で、同期処理だと、飯が炊けるまで豚汁の具を準備することも、サバを焼くことも出来へん。
やっと飯が炊けたら、次は豚汁の具を切り、煮込むわけだが、具材に火が通るまで、鍋の前で待っていなければならず、チャーハンの準備も出来へん!自分の飯なら良いが、これが茶店のランチとかだったら大災害である。
グーグルマップとかに、「昼休みを返せ」とか、「一生行きません」とか「はよ潰れろ」などという心無いレビューが殺到することが目に見えている。こんなんじゃあかん。
で、Promiseと非同期処理である。
飯を炊飯器にセットしておくと、飯が炊けたら、炊けましたっていうブザーなりなんなりの合図が来るやん。それがまさにプロミスである。
で、その合図が来るまでに、例えば豚汁の具を刻む、鍋で煮る。鍋が煮立った頃に、これまた知らせてくれる。まさにプロミス。
プロミスは、その処理が成功か失敗か、途中なのかのステータスと、処理が成功した場合は、その成果物(ここでは炊けた飯、煮えた豚汁)を返してくれる。
もし、炊飯器が破壊されて飯が炊けんかった場合は、ちゃんと”炊飯器爆破”というエラーを返してくれる。
おかげで、他の作業をしていても、プロミスが成功し、炊けた飯が返ってきたタイミングで、チャーハンにとりかかれるというわけや!!つまり、非同期で、各作業が別々に同時的に行われている。
で、サバが焼ける頃には、豚汁はちょうど良い具合になっており、チャーハンも出来上がっているという”晩飯を作る”というタスクがコンプリートする。
上に書いたように、Promiseっていうのは、上から下のフローから自由になり、作業が完了したら合図と成果物を返してくれるっていう、すごく便利な関数なわけだ。
以下は典型的なPromiseを作るコード。100歳以上を切り捨て、エラーを返す処理である。

function promiseFunction(age) {
    return new Promise((resolve, reject) => {

        if (age < 100) {
            resolve("お前は、まだイケる");
        } else {
            reject("お前はもう、死んでいる");
        }
    });
}

promiseFunction(101)
    .then(result => console.log(result))
    .catch(error => console.error(error));

new Promise でプロミスオブジェクトを作り、return でそのオブジェクトを返している。
で、Promiseのコンストラクタは(resolve, reject)の2種類のコールバック関数を引数にとると決まってる。
resolve()は、成功した場合の値を返し、reject()は、エラーが発生した場合にこの値を返す。
簡単に言うと、処理が成功した場合はresolve()がトリガーされ、失敗したらreject()がトリガーされる。

Async/Await

で、このプロミスの性質を利用したのが、ASYNC/AWAIT構文。
問えば、上記のチャーハンを作る関数を考えてみると、

const cookFriedRice = async() => {
    try {
        const rice = await cookRice();
        const friedRice = await fryRice(rice);
        console.log("Oishi!!!");
        return friedRice;
    } catch(err) {
         console.log(err.message);
        throw err;
    }
}

となる。
Await をプロミスを返す関数の前に付けると、その作業が終わるまで次のコードを実行せずに待ってくれる。
つまり、ライスが出来たら、次のfryRice()に渡せるようにする。もし、これを普通の関数として実行すると、ご飯が炊ける前に、fryRice();関数が実行され、飯無しチャーハンが出来てしまう。
なぜなら、cookRice()もfryRice()も非同期関数で、上から下のフローとは無関係に動いているからである。非同期ファンクションをオーダー通りに実行させたい時に、async/await を使う。ちなみに、プロミスを返さない普通の同期ファンクション、例えばconsole.log にawait を付けても、何も起きない。
で、このasyncを付けたcookFriedRice関数自体もプロミス関数と化す。
つまり、チャーハンが出来た時点で、fullfiled か rejectを返してくる。また、friedRice をreturn しているので、調理できたらチャーハンが返ってくる。
晩飯の例で言うと、

Promise.all([cookFriedRice(), cookSaba(), cookTonjiru()])
    .then(results => {
        console.log('Dinner completed successfully', results);
        eat(results);
    })
    .catch(error => {
        console.error('Dinner failed to resolve', error);
    });

とすると、全部の料理が出来たら、食べる という処理が出来る。
普段ワシらが普通にやってるマルチタスクなんで、特に理解が難しいわけではないと思うんじゃ。

最後に、自分がJavaScriptの勉強でメチャ役に立った教材を。

Net Ninja のチュートリアルにハズレなし。

この計算機アプリのチュートリアルは、JavaScriptの理解に個人的にメチャ役立った。

Reactなんかのフレームワークを使う際、Array functionは必須。メチャよく使う。

あかん。。。。ここまで書いたらまたしんどくなってきた。JavaScriptしか書けんかった。。。サーバーとフレームワークはまた次回という事で許して。。。ゲフっッッッッっ

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
430