第十回: 辞書に関数を入れる
第七、八、九回と三回に渡って関数をやってきました。
第十回では、その関数を辞書に入れる、という話をします。 辞書は第六回でやった辞書です。
関数についてはもうやってきたし、辞書に入れるのは、見た目はゴテゴテしているけれど、数字や文字を入れるのと変わらないので、第六回の内容と同じです。 ただ、見た目がゴテゴテするので、それに慣れる為にも少し説明をしていきたいと思います。
また、一つだけ関数が文字や数字と違う所があります。
それは関数は辞書に入れると、this
という特殊な変数の意味が変わる、という不思議な現象があります。
どう変わるかを一言で言えば「this
が、自身が入っている辞書を表す」というのがその内容なのですが、
後半では、そのことについて説明していきます。
なお、このシリーズでちゃんと理解しておいて欲しい内容は今回が最後になります。 次の第十一回は理解してなくても、実際上はそんなに困らない内容になりますし、第十二回はおまけです。
しかも実は、今回の内容も知らなくてもそんな困りません。
今回の内容については、なんだか分からない事もあるが、回りのコードを真似しておこう、でほとんどのケースで困りません。
ただ、分からない所があると気持ち悪い、という完璧主義な人のために、
理屈もちゃんと説明しておこう、という回になります。
関数を辞書に入れよう
JavaScriptでは、ある程度プログラムが大きくなってきたら、関連する関数を辞書に入れて使うのが一般的です。
このシリーズでもプレーヤーにボタンを押させる物はMessageBox
という辞書に入れてあります。
これを自分でもやっていこう、というのが今回の内容になります。
では自分で関数を作って、それを辞書に入れて行きましょう。
「むぇーー」という関数を辞書に入れる
実際にやってみましょう。 例えば以下のような関数があったとします。
あとの都合の為に関数名だけ鳴くということでnaku
になっていますが、
他は今となっては説明は要らないでしょう。
これをawaという辞書に入れたいとします。
ただ最近あまり辞書って使ってなかったので、本題の前に辞書について、今回使う範囲で簡単に復習しておきます。
辞書の復習
という事で、第六回の内容を簡単に復習しておきます。
復習という事でさらっと流すので、以下を読んで忘れているな、と思った人は第六回や、第6.2回: 辞書100本ノック!や第6.3回: 辞書と配列混合、100本ノック!の最初の方をやり直すなどしてみて下さい。(今回はそんな難しいのは使わないので、最初の方だけでOK)
辞書というのは、以下のように書く物でした。
var awa = {};
awa["toot数"] = 41030;
awa["フォロー数"] = 145;
awa["フォロワー数"] = 230;
また、例えば以下のようにキーをローマ字にすれば、
var awa = {};
awa["toots"] = 41030;
awa["follows"] = 145;
awa["follower"] = 230;
以下のようにawa["toots"]=
をawa.toots=
のように書いたり出来る、という話もありました。
var awa = {};
awa.toots = 41030;
awa.follows = 145;
awa.follower = 230;
この機能は第六回ではあまり使わなかったので忘れているかもしれませんが、今回は良く使うのでここで思い出しておきましょう。
また、最初から、以下のように書いても同じ事でした。
var awa = {
toots: 41030,
follows: 145,
follower: 230
};
さらに、辞書に配列をもたせる事も出来る、という話をしました。以下のnakuとかが配列です。
var awa = {
toots: 41030,
follows: 145,
follower: 230,
naku: ["むぇーー", "コケー", "ごあーん"]
};
こんな感じですね。 最後は、以下のようにも書けます。
var awa = {};
awa.toots = 41030;
awa.follows = 145;
awa.followers = 230;
awa.naku = ["むぇーー", "コケー", "ごあーん"];
こうすると、以下のような辞書が出来るのでした。
キー | 値 |
---|---|
toots | 41030 |
follows | 145 |
followers | 230 |
naku | ["むぇーー", "コケー", "ごあーん"] |
今回使うのはこの位です。 今回の前半の内容は、今回新しくやる事よりも、むしろこの第六回の内容が難しい、という回になりそうです。 詰まったら第六回復習、という感じでお願いします。
辞書に関数を入れよう。
さて、本題に戻りましょう。
こんな風にいろいろ入れられる辞書に、以下の関数を入れてみよう、というのが今回のテーマです。
var naku = function() {
MessageBox.show("むぇーー");
};
このnaku
という関数を辞書に入れます。
先程の、配列とかを置いてある場所を、この関数に置き換えればいい訳です。 例えば以下のようになります。
var awa = {};
awa.toots = 41030;
awa.follows = 145;
awa.followers = 230;
awa.naku = function() {
MessageBox.show("むぇーー");
};
nakuの所を、awa.naku = ["むぇー"]
などの代わりにawa.naku = function() {...};
としている訳です。(…は中略って意味で書いてます)。
こうすると、以下のような辞書が出来ます。
キー | 値 |
---|---|
toots | 41030 |
follows | 145 |
followers | 230 |
naku | function(){ MessageBox.show("むぇーー"); } |
上の辞書と見比べると、nakuの所だけが違います。 配列を入れる代わりに関数を入れている訳です。
なお、同じコードをこう書いても構いません。
var awa = {
toots: 41030,
follows: 145,
follower: 230,
naku: function() {
MessageBox.show("むぇーー");
}
};
これで辞書に、naku
をキーとして関数を入れる事が出来ました。
呼ぶ時はawa.naku()
とやると呼ぶ事が出来ます。やってみましょう。
普通の関数はnaku()
というように使いますが、辞書の中の場合はawa.naku()
のようになる訳ですね。
一つの辞書に複数の関数を入れる事も出来ます。 複数の関数を入れるとこんな感じになります。
見た目は複雑に見えますが、辞書の中に配列を入れるのとそれほど変わりません。むしろ配列の中に辞書をいれる、とかは無いので、
慣れるとこっちの方がずっと単純です。
以上で今回のテーマの前半、関数を辞書に入れる、という事が出来ました。
ここまでの話は、理屈の上では新しい事はそれほどありません。 今回やけに解説が早いなぁ、と感じたかもしれませんが、新しい事が少ないのであまり書く事が無いんですよねぇ。
でも、見慣れない物なのである程度慣れるまでは分かりにくいと思います。
こういう時は、理屈よりも手を動かす。 つまり課題をいろいろやるのがオススメです。
という事で幾つかやってみましょう。
課題: 蕎麦充する関数を辞書に入れよ。
るーひー、という事でru_hi_
という関数を作っておいたので、
これをlucyという辞書に入れて下さい。キーはhiru
とします。
何を言っているか分かりにくければ、お嬢様側のコードから推測してくれてもいいです。
なお、ru-hi-じゃなくてru_hi_なのはJavaScriptではマイナスは関数名には使えないからです。(どうでもいい話)
一つ目は問題の意味が良く分からなかったと思うので、似たようなのをばんばんやって行きましょう。
課題: こーしーか麦茶の関数を辞書に入れよ
今度は少し関数を複雑にしてみました。
situmon
という関数を、lucy辞書に入れてください。
キーはsitumon
とします。
ここでちょっとお嬢様側コードを見ると、以下のようになっています。
lucy.situmon();
MessageBox.show(lucy.nomu);
lucy.situmon
で関数を、lucy.nomu
で文字を取り出している訳ですね。
関数は後ろに()
をつける事で使う事が出来る、というのを第七回でやりました。
この「辞書から取り出す」というのと、「関数を使う」というのを組み合わせている訳ですね。
さすがに第十回まで来るとこれまでやってきた物もたくさんあるので、いろいろコンボが出来る。
もうひとつ似たようなのをやってみましょう。
課題: むぇーかコケーの関数を辞書に入れよ
やはり次はむぇーでしょう。 いつものように、ニワトリかどうか聞いてあじゃの鳴き声を選ぶ関数、situmonをこちらで用意しておきました。 これをkumosaba辞書にawaというキーで入れてください。
この説明が分かりにくければ、お嬢様側のコードから何をやるべきか予想して書いてください。
次は後から入れるのでは無くて、辞書を作る時に入れるパターンをやってみます。
課題: むえーの関数を辞書に入れよ
辞書は一旦{}
で作って後から入れる他に、
作る時に{lucy: "蕎麦充した"}
という風に指定する事も出来るのでした。
百本ノックの第6.2回あたりでやりましたね。
この形式で関数を入れる練習もしておきましょう。
kumosabaという辞書のawa
というキーに、"むぇー"
と表示する関数を入れて下さい。
今回は関数も自分で考えて書いて下さい。
ここまでは辞書に入れる側でした。
次に辞書を使う側もやってみましょう。
課題: 蕎麦充した後流れは無職せよ
kumosaba辞書を使って、"蕎麦充した"
と表示した後に、"流れは無職"
と表示してください。
今回はお嬢様側です。
もうひとつ似たようなのをやってみましょう。
課題: こちんこちんでない、ぬっくぬくなこーしーをしゅるしゅるせよ
lucy辞書を使って順番にメッセージを表示していき、
「こちんこちんでない、ぬっくぬくなこーしーをしゅるしゅるした」
という順番になるように関数を使うコードを書いてください。
この辺は問題文の意味を理解するのが難しい、という感じかもしれませんね。
もう少し呼び出す側をやってみましょう。 次は少しひねって,乱数を使ってみます。
課題: やれbotを乱数で作れ
yareという辞書をこちらで用意したので、これに入っている関数をランダムで呼んでください。全部呼ばれるようにする事。
ヒント: ifとかelse ifとか5個くらい必要です。また、乱数を使います。「こんなん出来るかー!」ってくらいは難しくて、結構長いです。
こんなに長いコードを自分で書くのはなかなか大変ですよね。
なお、理屈は説明しませんが、上級者的には以下のようにも書けます。
var keys = ["jiisiki", "kintore", "kike", "suki", "rikai"];
yare[keys[Math.randomInt(5)]]();
こういう書き方が出来るのはJavaScriptという言語の面白さなのですが、まずはifとelseでちゃんと書けるようになるのを目指しましょう。
といってもなかなか一発で正解、とは行かないですよね。 もう一つ似たようなの行ってみましょう。
課題: 労働botを乱数で作れ
上とほとんど同じなので説明はいらないでしょう。 辞書の中の全部の関数をランダムに呼ばれるようにしてください。
こんなの書けたら大したもんですよねぇ、ほんと。
最初しばらくは、答えを見たら理解は出来ても、なかなか自分では書けない、という感じだと思います。 こういうのは経験です。このシリーズ終わったあと実際にいろいろ書いていく中で書けるようになっていけば良いと思います。
次はちょっと趣向を変えて、もうちょっと実践的なセッティングでやってみましょう。
課題: こちんこちんに冷えた麦茶をしゅるしゅるせよ
以下に辞書と呼び出すコードがありますが、辞書の側が不完全です。
呼び出す側のコードを見て辞書に何が足りないかを考えて、必要な物を追加してください。
最終的には順番にメッセージが表示されて、つなげると"こちんこちんに冷えた麦茶をしゅるしゅるした"
となるようにしてください。
今回の問題のように、片方のコードは分かってる、という状態で、もう片方を予想するというのは、
実際に物を作る時には良くあります。
予想する為にはそもそも両方を書けるくらいの実力が必要なのでなかなか最初のうちは難しいですが、これも経験でございます(今回こればっか)。
もう一問似たようなのをやっておきましょう。
課題: るーひー、蕎麦が呼んでる、せよ。
一つ前の課題とほとんど同じです。呼ぶ側を参考に、lucy辞書を完成させて、"るーひー"
と表示された後に"蕎麦が呼んでる"
と表示されるようにしてください。
第10回ともなると、ここまでやってきた要素が結構いろいろあるので、組み合わせるとどんどんいろんな問題が作れてしまいますね。
キリが無いのでこの辺にして次の話題に進みますか。(作る方も大変なんですよ、ほんと…)
thisという名の変な奴
さて、第十回の後半の話題にうつりましょう。this
です。
関数を辞書に入れると、this
というのが、入っている辞書を表すようになります。
これは凄く変な振る舞いをする特別な奴なので、ここで説明しておきます。
this
は少し入門からははみ出して中級編の話題と思いますし、
プラグインを書く時には最初のうちは理解してなくても問題無いと思いますが、
一つ上へのステップに進む時のとっかかりのためにも簡単に説明しておきます(そんな難しくも無いので)。
thisとは何か?
とりあえずthisを表示してみましょう。 たとえば以下のようなコードでthisを表示出来ます。
このようにすると、辞書awaの内容が表示されます。
(なお、prototypeとかlengthとか変なのも表示されますが、それはこの課題システムの都合なのであまり気にしないでください。すみません。)
で、関数が辞書awaに入っているので、this
はこの辞書を表す訳です。
this
が辞書を表すので、このnaku
関数の中では、awa.toots
と書くのとthis.toots
と書くのはまったく同じ意味です。
やってみましょう。
このように、この場合はthis
と書くのとawa
と書くのは全く同じ意味になります。
また、関数でこのthis
の辞書の中身を書き換える事も出来ます。
関数には作る時と使う時の二つがあって、作るだけでは実行されない、というのを第七回でやりました。
で、このように、関数の中では、this
で自分が入っている辞書の要素を取り出したり、要素を変更したり出来ます。
this
がどの辞書を表すのか、さえ分かってしまえば、あとは第六回とかの内容となります。
理屈としてはこれだけです。
ですが理屈だけでは良く分からないと思います。 そこで次に、実際にどう使われるかを、課題をいろいろやって見ていきましょう。
awaと同じならなんでthisなんてあるの!?
本文で、この場合は変数awaとthisの指す物が同じ、という話をしました。
すると鋭い読者なら「同じなら別にthis
なんて要らないじゃん!」と思うかもしれません。
それはおっしゃる通りなのですが、その疑問にはちょっとこのシリーズのレベルではうまく説明出来そうにないので、「必要性は良く分からんがこの場合はawaと同じ意味になるんだな」と思っておいて下さい、
というのがこのシリーズでの答えとなります。
一応より難しい話をコラムとして書いておきます。
直接的な事を言うと、複数の辞書に同じ関数を入れる、という場合があるのです。例えばcounter()という関数を辞書に入れて、一回実行する都度入っている辞書のtootsを1増やす、という事をやるとします。
この場合、辞書awaにも辞書lucyにもこのカウンタが入っている場合、awa.counter()とlucy.counter()とやった時に、それぞれの辞書のtootsを1増やしたい、みたいな事があります。
別々の関数を入れればそれぞれawa.toots = awa.toots + 1;
とlucy.toots = loocy.toots + 1;
と書けばよいのですが、これを同じ関数でやりたい、という場合がある。
こういう時にthisと書いておけばどちらも同じ関数で、それぞれの辞書のカウンタを増やす事が出来ます。
これはゲームで同じ性質を持ったスライムを4体出現させる時とかに、それぞれが同じ処理をしたい、というような場合に便利です。
そしてこれをより使いやすくする為のprototype
という仕組みがJavaScriptにはあります。
prototype
については第12回で軽く触れますが、細かい理屈は本シリーズの対象外の、中級の話となります。
一つの関数を複数の辞書に入れるのは、オブジェクト指向プログラミングという物の基本となります。
このコラムもちょっと難しすぎて良く分からないかもしれませんね。本シリーズの範囲ではこの辺の事は分からなくてもOKです。
ある程度実際にコードを書いてみた後でないと分からない部分なので、このシリーズを終えた後にしばらく自分でプラグインとかを実際にいじってみて、経験が溜まったらこの辺の事を勉強しなおしてみてください。
分からなくていいなら書くな!というとそうなのですが、最終回が近いので、劇場版とか2期目の伏線みたいなのが入るのです。でも二期目は無かったりします。人生そんなもんです。
課題:鳴き声をむぇーに変えよ
以下のmochika関数で、辞書awaの鳴き声を「むぇー」に変更してください。 表示としては「コケー」と表示された後に「むぇー」と表示されるのが目標です。
なお、まちがえた時のメッセージは、0番目から数えるので、「1番目がむぇーじゃない!」とは、二つ目に表示されたメッセージが違うという事を意味します(以下の課題でも同じ)。
一つ目は勝手がつかめないかもしれないので、もう一つ似たようなのをやってみましょう。
課題:雲鯖大人気にせよ
以下の関数を変更して、表示されるメッセージを「雲鯖は大人気」になるようにせよ。
次はもうちょっと実践的な奴をやってみましょう。
課題:toot数を増やす関数、paoを作れ
以下のawa.pao()が実行される都度、toot数が1増えるようにせよ。
ヒント:変数の数を1増やす方法は、第三回の「JavaScriptの=は、普通のイコールと意味が違う」のコラムなどを参考にすると良いかも
もう一問くらい同じような問題をやってみましょう。
課題:toot数を一気に100増やす関数、cheatを作れ
前問と同様に以下のawa.pao()が実行される都度toot数が1増えるようにして、 さらにawa.cheat()が実行されたらtoot数が100増えるようにせよ。(関数を二つ作ってください)
ヒント:変数の数を1増やす方法は、第三回の「JavaScriptの=は、普通のイコールと意味が違う」のコラムなどを参考にすると良いかも
次はやはり、しゅるしゅるしましょう。
課題:ぬっくぬくなこーしーをしゅるしゅるせよ
paoを書きなおして、
- ぬっくぬくな
- こーしーを
- しゅるしゅるした
と表示するようにせよ。
ヒント: MessageBox.showを使って下さい
次はもうちょっとパズルっぽい課題をやってみましょう。
課題:もぅ、しみっしみ、もぅ、せよ
updateを書きなおして、
- もぅ、
- しみっしみ、
- もぅ
と表示するようにせよ。最後に「、」が無いのがポイントです。見た目より難しい問題です。(書く量は短いけど)
ヒント1: showがちゃんとは理解出来なくても、なんとなく分かるくらいでupdateを書く事は出来ると思います。
ヒント2: 中身のない文字、""
を連結すると何も起きません。例えば"むぇー"+""
は"むぇー"
になります。
ヒント3: 二番目が「もぅ」じゃない、と言われたら、ゼロ番目から数えるので三つめのメッセージの表示が違う、という事です。
なお、updateはもうちょっと難しい書き方で、
var lucy = {
// ...中略...
show: function() {
MessageBox.show(this[arguments[0]] + this.sep)
},
};
lucy.show("mou");
lucy.show("simisimi");
lucy.update();
lucy.show("mou");
という感じの問題にしようかとも思ったのですが、ここまで難しくしなくても良いか、と思って上のような問題になりました。 興味があったらこの難しい書き方版もどういう意味か考えてみてください。
課題:こーしーと麦茶を両方しゅるしゅるせよ
呼び出す側のコードから推測して、lucy辞書に必要な要素を追加してください。 実行したら、
- ぬっくぬくなこーしーをしゅるしゅるした
- こちんこちんに冷えた麦茶をしゅるしゅるした
が順番に表示されるようにMessageBox.showしてください。
ヒント:「を」は自分で足してください。"を"
と書いちゃっていいです。
最後に配列とかも混ぜ、現実のプログラミングで割と良くある感じの課題をやって終わりにしましょう。
課題:ぬっくぬくでないこちんこちんなあれをあれせよ。
lucy辞書に必要な関数を足して、
- ぬっくぬくでない
- こちんこちんに冷えた
- 麦茶を
- しゅるしゅるした
と順番に表示されるようにしてください。 呼び出している側から何が必要かは推測して書いてください。
こういうコードはいかにも実際にある奴なのですが、
課題としては少し難し過ぎる気もしますね。
答え自体は短いのですが、考え方みたいなのが難しい。
最後にちょっとおまけとして難しい話をしておきます。
thisは呼び出す時の値になる(分からなくていいです)
この部分は分からなくても良い解説です。 ラスボス倒した後の99階まであるダンジョンとでも思っておいて下さい。クリアには必要ありません。
thisというのは、関数を実行する時に、その関数が入っている辞書を表します。 作る時ではありません。
例えば以下のコードを実行してみましょう。
関数は全く同じ物でも、呼ぶ時にどの辞書に入っているかでthis
の値は変わります。
イメージとしては、お嬢様がセバスチャンにLINEで用事を言いつける場合に、
「あなたが今居る
ポケモン預かりボックスからイーブイを連れてきなさい」という風に言うのに相当します。
セバスチャンは同一人物でも、指示を受けた時にどのポケモン預かりボックスに居るかで結果が変わる訳です。
今居るポケモンボックス
というのがthis
に相当します。
お嬢様が頼む時にセバスチャンが今どこにいるか、それを表すのがthis
です。
なお、プラグインではこれを偽装する事でシステム自身の挙動を変えずに自分の処理を挟み込む、という事をやります。
何を言っているのか分からないですね。さすがにこの辺は分からなくていいです。思わせぶりな事を言いつつ結局回収されなかった伏線とでも思ってください。(ダメじゃん)
第十回 まとめ
なかなか課題が多い回ですが、やった事自体は多くはありません。
- 関数は辞書の中に入れる事が出来る
- 入れ方は辞書を作る時に
{nakigoe: function(){...} }
みたいに入れる方法と、辞書を作った後にawa.nakigoe = function(){...};
とイコールで入れる方法がある - 辞書に入れた関数を使うと、関数の中で
this
という物が使える this
はその関数が入っている辞書を表す
以上です。
細かい話はあまり理解してなくても良くて、関数は辞書に入れる事が多い、 という事だけわかっていればとりあえずは合格です。
このシリーズの全体的な話
この「算数で挫折した人向けの、JavaScript入門」シリーズ、新しい機能という点では、大きな物はこの第十回までで終わりの予定です。
ここまで挫折せずに来たなら、本シリーズで伝えたい事は全て伝えられたという事になります。
もしここまで来れたなら、おめでとうございます。
あなたはJavaScriptの入門としては十分過ぎる所まで来ているでしょう。
実際、第十回の内容は、どちらかといえば中級でやる事です。関数もarguments自体は中級の内容になるので、第九回も半分くらいは中級です。
本屋さんでJavaScriptの本を立ち読みしたら、この辺の話は入門の本には書いて無いと思います。試しに本屋に行ったら見てみてください。
ここ何回かの課題を見れば分かるように、ここまでやった内容は、一つ一つは小さな事でも全部組み合わせると相当いろいろな事が書けます。
個々の要素が分かる、という事と組み合わせて作りたい物を作る事はまた違う難しさもありますが、
組み合わせて作る練習は「勉強」の次のステップで、実際に作りながら学んでいく物です。
勉強の段階では個々の要素が分かる所までで十分です。
勉強するだけで作れるようにならないのはどこの世界でも一緒ですよね。
なので逆に言えば、勉強としてはその手前まで行けば、十分マスターした、と言って良いです。
実際にいろいろ作り始めるまでが勉強の役割、書いていく内に分かっていく事は勉強の次の段階で分かる事なので、勉強の段階では分からなくてもOKなのです。
そういう点では、このシリーズの課題の幾つかはその枠を超えています。
それらを出来なくても「勉強」の段階は終わったと言って良いでしょう。
さて、第十一回はこれまでやった事と全く同じ事を違う方法でも書ける、という話になります。
出来る事は一切増えないのですが、人のコードを読む時などに知らない書き方をされていると戸惑う事もあるので、
良くある書き方は一応見ておこう、というのが第十一回の趣旨になります。
ただ出来る事は増えません。
第十二回は、おまけとして実際のプラグインのコードを読んでいこう、という内容の予定です。
第十一回まではツクールMVの内容は一切関係無い、JavaScript全体の話でしたが、
第十二回だけはツクールMVの話をしようと思います。
説明がもれている要素を補ったりもしますが、どちらかというと「理解しないでどう乗り切るか」という話になります。
プログラムは「7割くらいは分かる」という所まで行ったら実際に書いていって学ぶのがオススメです。
そこで「分からない3割を乗り切る」というテクニックも必要となります。