2020-03-13

Node.jsで仮想通貨の自動取引(bitFlyer編 #4) Realtime API公式コードを読む(2)

今回からはSocket.ioのお話に入っていく。またfor文のin,ofに関しては詳しく説明してみる。

Article Image

今回解説するコード

// connection handling
socket.on("connect", () => {
    // subscribe to the Public Channels
    for (const ch of publicChannels) {
      //この内側は次回
    }
  
  //以下は別の回で

なんとたったこれだけを徹底的にやっていく。JavaScript全般の勉強にもなるため自動売買のプログラムやAPIとは関係なくなるが私なりに解説していくので理解えもらいたい。

今回はどちらかというと初心者を脱出する前ぐらいの人向けの記事となるのでご了承願いたい。

最初の行 .on

すでに最初の行が意味不明な人も多いだろう。

socket.on("connect", () => { ... }

まず先頭のsocketは前回解説したので省略するとして次のonメソッドが呼ばれている。

socketで定義したところに「onを実行してね!引数はAとBだよ!」と言っている。

この行ではonconnectを渡して単純に接続を確立する処理だ。接続するときはコレと決められている。それに関してはこれ以上説明は必要ない。(このconnectも定義されており勝手に変更などは出来ない)

2020/03/15追記:onは厳密にはサーバーからのイベントを待ち受ける「受信」のメソッドだ。次回イベントを発火する「送信」側(emit)を説明するので頭の片隅にonが受信であることを意識えおく。

onの構文

構文が少し難しい点と第二引数は各自で変わるので説明していく。この構文はシンプルに表現すると

socket.on( 引数A , 引数B )

という構造なっているだけだ。しかし「引数Aが"connect"なのは分かる。でも引数Bのとこ() => {}になってないか?引数なのこれ?」最初はこういう思考になるだろう。

これはアロー関数というJavaScriptの概念だ。つまり引数に関数を渡している。まずはアロー関数から覚えておこう。

色々訳あってfunction定義だと不便じゃないかということで出来た。通常のfunction定義はこうだ。

const A = function(B) {
  //ここになにか処理
}

こうだったものを

const A = (B) => {
  //ここになにか処理
}

と書いても良くなったと考えておけばOKで、どちらもほぼ同じ意味だ。(厳密にはちょっと違うので気になる場合はより詳しい情報をGoogleで調べてみてほしい)

ということは () => {} は 左側のカッコの中にはこの関数の引数を、右側のカッコの中には処理を書くことになるが、重要なのは「この関数自体を纏めて引数としてonに放り込んでいる」というところだ。

この処理を言葉で表すと「onさん "connect" して 成功したら (引数) => {処理} をお願いね!」と言っている。

そしてその処理の中身がこの続きに入っている。ここでは () が空白になっているので引数は渡さないで次に移行する。

たぶん全然わからない人も多いと思う。その場合は必死でアロー関数やコールバック関数の意味を調べてほしい。

もう一度言うがonには引数として関数を渡しているという感覚が理解できればOKだ(これをコールバック関数という)

次のfor文

さて、すでに混乱したかと思うが次もちょっと混乱する。準備はいいか?だめか。

 for (const ch of publicChannels) { ... }

さすがにfor文がわからない場合は初心者すぎるので他を当たって欲しい。問題なのはofだ。

実は説明するのは簡単なのだが、なぜ混乱すると書いたかというとこの書式にはof以外にもinというのがあるからだ。まずはofから説明する。

通常のforならばfor(let i = 0 ; i<=なにか数字 ; i++) {...} になっていることが多い。しかしここは()内がシンプルにまとまっている

まずpublicChannelsは#3で説明した定数の配列だ。実際には["lightning_executions_BTC_JPY"]コレ1つしか入っていない。

このofの構文は

publicChannelsという配列から1個づつ取り出して終わるまでループしてね!取り出した1コは constchに入れて中の処理を実行するよ!

という意味だ。i++を使うよりもシンプルで分かりやすい記述になっている。

ではちょっと別のコードを作って実行結果を見てみよう。

//テストコード
const asset = ["BTC","ETH","タンス預金"]

for(const a of asset){
    console.log(a)
}

//実行結果
BTC
ETH
タンス預金

さて、思ったより簡単だっただろうか?これはかなり使える。

しかし、どうせofをやるならいずれ必ずinで躓くのでofの代わりにinを置いて実行してみよう。

//テストコード
const asset = ["BTC","ETH","タンス預金"]

for(const a in asset){ //ここが of から in に変わっている
    console.log(a)
}

//実行結果
0
1
2

実行結果が意味不明である。3つカウントしただけではないか。

これは公式ドキュメントによると「列挙可能プロパティ」に対して繰り返すらしい。これはモノによって変わるのだが**配列の場合は要素番号、オブジェクトの場合はキー名**となる。

これではピンとこないと思うのでオブジェクトをinでループしてみよう。

//テストコード
const asset = {"北尾さん":"BTC","アーサーさん":"XRP","加納さん":"タンス預金"}

for(const a in asset){
    console.log(a)
}

//実行結果
北尾さん
アーサーさん
加納さん

見事にキー名だけ表示された。値も取りたければasset[a]とすればOKだ。

オブジェクトにオブ(of)はダメ

と、暗記しておこう。(少々強引ではあるが)

英語の感覚があるなら オブジェクトにオブはオブジェクション(反対)と覚えたらスマートかもしれない。

for...of と for...in 応用編

inofにはいろいろなケースがあると思うが応用も見ておこう。

配列の中にオブジェクトが列挙されている場合

//テストコード
const asset = [ //外は配列
    {"aさん":"BTC","所持数":"2"}, //中はオブジェクト
    {"bさん":"ETH","所持数":"3"},
    {"cさん":"XRP","所持数":"4"}
]

for(const a of asset){
    console.log(a)
}

//実行結果
{ 'aさん': 'BTC', '所持数': '2' }
{ 'bさん': 'ETH', '所持数': '3' }
{ 'cさん': 'XRP', '所持数': '4' }

あくまで外側が配列なのでof。個人的によくみる形だ。混乱しないように。

オブジェクトの中にオブジェクトの場合

//テストコード
const asset = { //オブジェクト
    "1a":{"aさん":"BTC","所持数":"2"}, 
    "2b":{"bさん":"ETH","所持数":"3"},
    "3c":{"cさん":"XRP","所持数":"4"}
}

for(const a in asset){
    console.log(a)  //aだとキー名だけなので
    console.log(asset[a]) //asset[a]も加える
    
    //さらに次で二重ループになる事も多い
    //for(const b in asset[a]){ bに処理 }
}

//実行結果
1a
{ 'aさん': 'BTC', '所持数': '2' }
2b
{ 'bさん': 'ETH', '所持数': '3' }
3c
{ 'cさん': 'XRP', '所持数': '4' }

この場合はオブジェクトをループしているのでinだ。

コメントにも記したが、こういう形式の場合はさらにforループが重なる事がよくあるので慣れておきたい。

さいごに

たった2行のコードでここまで徹底的にやったが、正直もっとやってもいい。だが、今日はここまで。覚えることは無限にある。長い道のりだ。



この記事をシェア


謎の技術研究部 (謎技研)