LoginSignup
0
0

More than 1 year has passed since last update.

骨までしゃぶりつくす「ぷよぷよプログラミング」(3/4)

Last updated at Posted at 2022-02-20

この記事の目的

 この記事では前々回記事

  • 目的1.「ぷよぷよプログラミング」で作成していく範囲のソースコードから javascript と html の技術を学んでいく

に沿ってソースコードを読み込んだ結果を記述しようと思います。記載する項目は私が学びがあったと感じたものだけで、すべての文法などを解説するものではありませんん。下に言及する項目の一覧を示します。

  1. HTML

    • 全般
    • <div style="display:none">
  2. Javascript ( ECMA Script )

    • 全般
    • クラスと静的プロパティ/静的メソッドと this
    • return の仕様
    • 定義されていない配列要素へのアクセス
    • オペランド ||
    • オペランド &&
    • キーコード
  3. Document Object Model ( DOM )

    • 全般

前置き

この記事はjavascriptに関しての入門者が書くので正確性を欠く場合があります。

HTML

全般

 実はぷよぷよプログラミングではHTMLのコード量は多くなく、たった45行です。HTMLの仕様WHATWGから確認できます。

<div style="display:none>

私が唯一なるほどなと感じたのは<div style="display:none>によるHTML要素の非表示です。このdivで囲まれたコード領域はDOMを介して操作できる状態にはあるものの、表示されなくなります。この非表示の要素をjavascriptからdocument.getElementByIdなどを利用して取得し、動的に位置などのプロパティを操作した後に、appendChildを通してブラウザに伝えることでぷよぷよの位置表示を実現しています。

Javascript

全般

Javascript の仕様はECMA Script の仕様 として定義されています。しかし、現状私は読んでも上手く理解できません。できればこういった一次情報から理解したいですが難しそうなので、しばらくはかみ砕いて技術紹介しているブログ等を読むことになると思います。

クラスと静的プロパティ/静的メソッドと this

 私が今回ソースコードを読み進めるにあたって最初に混乱したのがこの項目です。JavaScript にはオブジェクト指向の class を定義する文法があるのですが、class 内で定義した静的メソッドや静的プロパティを理解するのに少し時間を要しました。余談ですが、JavaScriptのclassは歴史的な拡張を経て用意されたシンタックスシュガーであり、プロトタイプと呼ばれる構文を簡易的に記述できる文法のようです。筆者もこのあたりの技術の関係性は執筆時点で詳しく理解していません。今回の「ぷよぷよプログラミング」を理解するために必要な情報だけ調べています。
 「ぷよぷよプログラミング」で定義する class はインスタンス化せずに class に定義された静的メソッド/静的プロパティを参照する形で利用されます。そういう意味では、ここでの class 定義はオブジェクト指向的な意味を持たず、処理概念の纏まりや命名規則程度の意味しか持ちません。
 さて、本題に話を移します。まず静的メソッドに関してですが class 内で static を文頭に付与したメソッドはインスタンス化したオブジェクトに属するものでなく、class そのものに割り振られます。したがって class名.静的メソッド名() のようにして呼び出すことができます。例にすると下記のようになります。

static_method.js
class SampleClass{
    static sample_method(){
        console.log("hello static method");
    }
}

SampleClass.sample_method();

「ぷよぷよプログラミング」ではこの静的メソッド内にthisを使った変数が登場します。これらの変数はクラス定義の最初にコメントアウトで静的変数だと書かれているのですが、なぜこれでクラスの外側からアクセスできるのか、しっくりきませんでした。インスタンス化する前提であれば当該オブジェクト内の変数である、というイメージがあったのですがsatatic_property.js のように書いた場合にはthis が指し示すオブジェクトはSampleClassそのものであるという認識が落ちていたからです。(コード内のコメントアウトを動作するように変更しても問題ありません。)

static_property.js
class SampleClass {
    // static sample_property;
    static sample_method(){
        this.sample_property = "toto";
        console.log(this.sample_property);
    }
}

SampleClass.sample_method();

私にとってはここのページが理解の補助となりました。上記を読んでみるとわかるように静的メソッドを定義するのは、関数プロパティを定義することに等しいようです。この説明を頭に入れておくと、幾分かスムーズに理解できるようになりました。

return

return を利用すると関数に返り値を持たせることができるのですが、単純にreturn した場合に何が返るのかがわかりませんでした。結論 undefined が返されます。

return.js
function ret(){return;}
const v = ret();
console.log(v);

上記の結果はundefinedとなります。return がundefined を投げる仕様もすべてを把握できていませんが、このあたりが 参考になります。一方で言語に対する正確な理解はECMA Script を読み込む必要があると感じています。「13.10 The return Statement」あたりを読むといいのだと推測しているのですが、記号の意味がわからず解読できていません…

定義されていない配列要素へのアクセス

突然ですが下記のarray_access.pyはどのように動作するでしょうか?2行目が特に気持ち悪いですね。liは3要素の配列なので、li[3]はインデックスの範囲を超えています。

array_access.py
const li=[1,2,3];
const li4=li[3];
console.log(li4);

結論、このコードは動作します。li[3] の部分はundefined を返して、コンソールにはundefined が表示されます。私はこの仕様を知らずにstage.js の50,52行目で困りました。というのもConfig.stageRows で Config.stageCols でステージのサイズを変更できるのですが、その前段のthis.board には固定サイズの配列しか用意されていないためインデックスサイズを超えたアクセスが実行されてしまうのです。定義していない領域にもアクセス可能で、それを前提にコーディングできるのは別言語での経験を持っていると少しとっつきにくかったです。

オペランド ||

もちろん、論理和を表すのですが…

operand.js
exp1 || exp2

と記述し、exp1 がtrue に変換可能な場合はexp1を返して、それ以外はexp2を返します。stage.js の50行目で利用されている書き方で初見では何をやろうとしているのか何となくわかるものの、少し気持ちが悪かったです。ここを参照すると理解できます。

さて、この記述からわかる通り、このオペランドが返すものはtrue/false とは限りません。下記のコードはundefined がコンソール出力されますし、

operand_undefined.js
console.log(undefined || undefined); 

下記はfugaがコンソール出力されます。

operand_string.js
console.log(false||'fuga');

オペランド &&

オペランド|| と同じように&&も他の言語とは一風変わった動作に感じます。exp1 がtrue に変換可能な場合はexp2を返して、それ以外はexp1を返します。
|| と同じように以下のコードはundefinedを返します。trule/falseを必ず返すとは限らないことを念頭に置いておく必要があります。

operand_undefined.js
console.log(undefined || undefined); 

下記はfugaがコンソール出力されます。

operand_string.js
console.log(true&&'fuga');

キーコード

キーボードからの入力に対するコードが存在します(参照)。アスキーコードとは別物です。player.jsの27~43行目あたりで登場します。
また、矢印キー入力に対してのデフォルトイベント処理を打ち消すためにpreventDefault() と呼ばれるメソッドがコールされています。こちらの記事 にわかりやすくまとめてありました。矢印操作はブラウザにとってスクロールバーを操作するデフォルトの機能を持つため、これを打ち消すために必要なのだと理解しました。

Document Object model

HTMLとCSSをブラウザが解釈して、その状態を保持するのですがJavaScriptを介して動的にその状態を操作することができます。その際に利用するAPIのことをDOMと呼びます。DOMはJavaScriptから利用する機能なのでECMAの仕様に規定があるのかと思っていたのですが、どうやら分離された状態で管理されています(参照)。仕様はW3Cが規定しており、このあたりから読み込んでいくといいのかなと思っています。
少しググるとAPIを検索できるサービスがあったのでこういったものを参照しながら学習するのがいいのかなと思いました。

ぷよぷよプログラミングで利用するDOM API

各APIの仕様は上記のAPIを検索できるサービスを調べればわかるのでそちらに譲ります。ここではこれらがわかっていれば、ぷよぷよプログラミングが少なくともDOMの観点では理解できるという意味でリストを提示しておきます。

  • getElementById
  • addEventListener
  • requestAnimationFrame
  • cloneNode
  • appendChild
  • addEventListener
  • preventDefault
  • removeChild
  • remove
  • requestAnimationFrame
  • insertBefore

最後に

次回

0
0
0

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
0
0