『Nostrでbot』を作った話の派生記事です。

せっかくなので、学んだJavaScriptの使い方を少しまとめていこうかと思います。いずれも演習を進めるにあたって雑に理解したものなので、テキトーな部分も多いですがご容赦を。

【JavaScriptの基礎の基礎】

☆とりあえず「const」☆

constで変数や配列や関数を定義します。演習のソースコードに頻出。何はなくともconst。3,4がなくて5にconst。

const name = "電王";
→ これは「name」という変数を定義して、初期値として「電王」を代入しています。文字列は原則として" "で囲まなければいけません
const riders = ["龍騎", "電王", "ディケイド", "オーズ", "鎧武"]; 

console.log(riders[0]); // 龍騎を表示
console.log(riders[2]); //ディケイドを表示
→ こちらは「riders」という配列を定義して、「龍騎」以下の値を代入しています。
  配列の中身は要素番号で参照することができます。要素番号は「0」から数えます。
  なので「riders[0]」を指定すると「龍騎」が参照されます。

  「console.log(  )」は(  )の中に指定された内容をコンソールに表示します。
  バグ潰しの強い味方、あっちにもこっちにも「console.log」を書いて、変数の中身などを表示しましょう。
const nakanoHito = ["城戸真司", "野上良太郎", "門矢士", "火野映司", "葛葉紘汰"];

console.log(riders[3] + "の変身者は" + nakanoHito[3] + "です");
 → 変身者の配列を定義してみましょう。
   ライダーの配列と変身者の配列を対応するように定義すると、同じ要素番号を使って「(オーズ)の変身者は(火野映司)です」という表示ができます。
const henshin = { 龍騎: "城戸真司",
                            電王 : "野上良太郎",
                            ディケイド: "門矢士",
                            オーズ: "火野映司",
                            鎧武: "葛葉紘汰"};

console.log(riders[4] + "の変身者は" + henshin[riders[4]] + "です");
 → ライダーと変身者を混ぜてみましょう。「キー:値」という形式の配列です。連想配列と言うらしいです。(なぜか「キー」部分は文字列を「""」で囲まなくても大丈夫らしい)
    ライダー名を「キー」に、変身者を「値」にすると、配列「riders」の要素をキーにして、値を参照することができます。consoleには「(鎧武)の変身者は(葛葉紘汰)です」と表示されます。

    冒頭で定義した「name」には今「電王」が入っています。なので
console.log(name + "の変身者は" + henshin[name] + "です");
    と書くと、「(電王)の変身者は(野上良太郎)です」と表示されます。

    普通の配列は[    ]、連想配列は{     }で囲まれていることに注意。


☆constは関数も定義できる☆

演習のソースコードには「=>」という記号も頻発します。
  const composePost = (content) => { ~~~~ };
こういう感じのやつ。「アロー関数」というらしい。
図書館で借りてきた本によると、
  function add(a, b){
     return a + b;
     }

という関数を
   const add = (a, b) => {
     return a + b;
     };
というふうにも書けるよ、ということらしい。
どっちも「a」と「b」という引数を受け取って、その二つを足し算した結果を返す、ということですね。
const sum = add(15, 20);
というふうに書くと、「addという関数に15と20という二つの引数を渡して、戻ってきた値をsumに代入しなさい、という意味になる。

(※constや変数定義に関するmattnさんからの補足1補足2。mattnさんありがとうございます!)

【では早速、演習1】

☆演習1-1☆

1-1は、リレーに対してイベントの取得リクエストを送って投稿を取得するプログラムです。

まず1行目に
const { currUnixtime } = require("./utils.js");
というのがあります。これは「currUnixtime」という関数が出てきたら同じフォルダの「utils.js」というJavaScriptファイルを見に行ってね、ということです。
他のプログラムでも共通で使う関数は別ファイルにして定義しておけば何回も同じの書かなくてすむ、ってことですね。

2行目は
require("websocket-polyfill");
よくわかりません。これもなんか機能をよそから取ってこいと言ってるんでしょう、たぶん。

リレーにリクエストを送る時には「JSON.stringify」というのを使って「JavaScriptオブジェクトをJSON文字列に変換」
リレーがメッセージを返してきたら今度は「JSON.parse」というのを使って「JSONデータをJavaScriptオブジェクトに変換」

よくわかりませんね?

ともあれ受け取ったメッセージを「msg」という変数に代入して、処理していきます。
メッセージの構造は

["EVENT", <対応するREQの購読ID>, <イベント>]

という形。
つまり「配列」になっています。
なので「switch」文で「1番目の要素が"EVENT"だったら、3番目の要素を表示してね、という処理を書きます。

要素番号は0から始まるので、
switch (msg[0]) {
     case "EVENT":
ということになります。

表示したいのは3番目の要素なので、指定としては[2]。
console.log(msg[2]);
これで一応正解では?と思うんですが、リレーが渡してくれる3番目の要素、中身はこんな感じになっています。
{
  "content": "こんにちは",
  "created_at": 1687926214,
  "id": "cca12345~",
  "kind": 1,
  "pubkey": "67890cc~",
  "sig": "cf987654321~",
  "tags": []
}

「キー:値」という連想配列のようになっていて、これの「こんにちは」の部分だけを参照したければ

msg[2].content

と書けばいいらしい。もし「pubkey」の部分を参照したければ

msg[2].pubkey

この「.」で繋ぐ「ドット記法」はJavaScriptの根幹なようで、やたらに出てきます。

《switch文》

複数の条件分岐を記述する形式
switch (式){
    case 値1:
    //式が値1と一致した場合
    break;
    case 値2:
    //式が値2と一致した場合
    break;
    default:
    //どれとも一致しなかった場合
    break;
 }


☆演習1-2☆

1-2は、1-1と同じことをNostr-toolsというライブラリを使ってやってみる課題です。なのでソースコードの2行目に
const { relayInit } = require("nostr-tools");
というのがあります。「relayInit」を「nostr-tools」から取ってきてね、という命令。

で、「Q-2: Relayオブジェクトのメソッドを呼び出して、リレーに接続してみよう」とか言われます。
オブジェクト…?メソッド……???
よくわからないけど「relay.connect」とか「relay.sub」とかいう、「.」で繋がったやつが「メソッド」らしい。ともあれ
relay.sub([{ kinds: [1], limit: 10 }])
と書けば「kind1」のイベントを10件取ってこれる。「since」「until」で日時を指定したり、「authors」で投稿者を指定したりもできる。
要は{ }で囲んだ連想配列を「フィルター」として渡している、ということっぽい。

1-2では1-1の「msg[2]」の部分が「ev」という変数に入るので、投稿本文である「content」部分だけを表示したければ、
console.log(ev.content);
となります。