JavaScriptの基本とイベントモデル

目標

ここでは、JavaScriptの基本的な書き方、変数や式、文などの概念について学ぶ。
また、WebページとJavaScriptの関係についても学ぶ。

  • script要素の使い方について理解する。また、JavaScriptのプログラムを書く3つの方法について理解する。
  • 定数、変数、式について理解する。
  • 文について理解する。
  • 引数を持たない関数について理解する。
  • JavaScriptで書かれたプログラムが実行される仕組みについて理解する。
  • イベントについて理解する。
  • イベントハンドラが書けるようになる。
  • alert()など、基本的な幾つかの関数について理解する。

JavaScriptの基本

プログラムの実行

多くのプログラミング言語と同様、JavaScriptのプログラムも宣言によって構成されており、基本的には上から下へ実行されていく。
文は、メモリに記憶している値を変えたりプログラムの流れを制御したりする処理である。
宣言は、処理の塊である関数などを定義する。
宣言では、関数などを定義をするのみで、実際にメモリに記憶している値を変えたり、計算をしたりはしない。
実際にメモリに記憶している値を変えたり、計算をしたりするのは、関数が呼び出されたときである。
より詳しくは、追って説明する。

実際にメモリに記憶している値を変えたりする処理について説明する前に、値そのものとそれを使った式について説明する。

データの型

JavaScriptでは、データを記憶するにあたり、次のような7つのデータの(タイプ)を規定している。
全ての値は、これらの型のどれかに属する。

Undefined型
変数に何も値が代入されていない場合に使われる型。値としてundefinedのみが規定されている。
Null型
値として、空を表すnullのみが規定されている。
真偽型(Boolean型)
真偽を表すための型。値として真(true)と偽(false)の2つが規定されている。
文字列型(String型)
文字列を表すための型。
Symbol型
オブジェクトのプロパティなどに使われる型。
同じ値を2つ以上作ることができない特殊な値を表すのに使われる。
数値型(Number型)
数値を表すための型。整数、実数の双方を表すことができる。
Object型
上記6つの型の組み合わせで構成される型。

定数とリテラル

JavaScriptでは、データとして先に述べた7つの型を扱うことができ、それぞれにその値(定数)を記述するための書き方がある。
この書き方のことをリテラルと呼ぶ。
ここれではそれぞれの定数のリテラルを紹介する。

Undefined型の値
Undefined型の値としてはundefinedのみが規定されており、値もそのまま「undefined」と表現できる。
ただし、正確にはundefinedはリテラルではない。
Nullリテラル
Null型の値としてはnullのみが規定されており、リテラルもそのまま「null」である。
頭文字が小文字でなければならないので要注意。
真偽リテラル
真偽値である真と偽はそれぞれ「true」「false」と記述する。
文字列リテラル
文字列をシングルクォーテーション(')またはダブルクォーテーション(")でくくって記述する。
ただし、シングルクォーテーションでくくった中にシングルクォーテーションを入れたり、ダブルクォーテーションでくくった中にダブルクォーテーションを入れる場合は、バックスラッシュ(\)をその文字の前につける。

例: '慶應義塾'"Keio University"'12345'"I'm a student.", 'I\'m a student.'

Symbol型の値
Symbol型の値を直接扱うためのリテラルは存在しない。
関数Symbol()を使うことによって、Symbol型の値を作ることができる。
数値型の値
整数を表す整数リテラルと実数を表す浮動小数点数リテラルが存在する。
整数リテラルには更に、10進法で表現する方法(123のように頭が0で無い数字で始まる)、2進法で表現する方法(0b10b10111のように頭が0bで始まる)、16進法で表現する方法(0x10x17のように頭が0xで始まる)などの方法がある。
一方、浮動小数点数リテラルにも、3.14159のように一般的な表現を使用する方法、6.022e23のようにeを使って表現する方法(この例では6.022×1023を表す)が存在する。
Objectリテラル
複数の値を組み合わせたもので、{"key1": "value1", "key2", "value2", ...}といった表現を使う。
"value1""value2"の部分は文字列リテラル以外にも任意のリテラルを使うことができる。

変数

変数とは、コンピュータの記憶領域の中に場所を用意して、その場所に名前を付けたものである。
変数には値を入れることができる。
言語によっては、数字しか入れられない変数、文字しか入れられない変数など、変数の使用用途がきまっているものもあるが、JavaScriptの場合どんなものでも同じ変数の中にいれることができる。

変数の概念

プログラムは、データをあるアルゴリズムに則って処理をする時の、処理手順を記述したものである。
料理をする時のレシピのようなもので、「炒め物」といった場合、おおざっぱに言えば、材料を切って、フライパンを使って油でいためて、味付けをする。
この時、材料がキャベツ/人参/玉ねぎだと野菜炒めができるし、ピーマン/豚肉/タケノコだったら青椒肉絲ができる。(ちょっと乱暴なのはご愛嬌で。)
ここでは「材料」が何かによってできるものが異なることとなる。
つまりレシピには、「何かを切る、何かをいためる、何かに味をつける」と書かなくてはならない。
この「何か」が変数である。
足し算などでも同じである。
c=a+b」と書き、「a」が3、「b」が5であれば「c」は8となる。
このように記号によって値を表現する。
ここで、数学でいうところの「c=a+b」と異なり、JavaScriptでは「a+b」の結果を変数「c」に代入するという意味になることに注意が必要である。

変数の宣言

JavaScriptでは、「この記号は変数です」ということを明確にするために、宣言文と呼ばれるものが用意されている。
JavaScriptにおいて明確に変数を宣言するためには下記のように行う。

var varname;
var varname = 初期値;

1番目の方法は単に変数を用意してそれに「varname」という名前をつけることを宣言しているだけである。
見た目上はなにも起こらない。
ここでデバッガを使って値を表示させようとしても、値が定義されていないので「undefined」になる。
2番目の方法では、「varname」という名前の変数を用意し、その中に初期値を代入している。
初期値の部分は、数字や文字、文字列のような定数でも構わないし、計算式やオブジェクトを生成するような式でも構わない。

変数の宣言と初期化を別々の行で行うこともできる。
たとえば上の2番目の方法を2行にわけて記述すると次のようになる。

var varname;
varname = 初期値;

実は、JavaScriptでは、明示的に変数の宣言を行わなくともプログラムは動作する。
しかし、このような使い方は問題を起こす場合が多いので、必ず変数宣言を行う方がよい。

変数名の付け方

変数の名前のつけ方にはルールがある。
変数名をつけるときには次のルールに従うことが必要である。

  • 使える文字は、英数字、アンダースコア(_)、ドル記号($)
  • 1文字目は上記のうち、数字以外
  • 大文字小文字は区別される
  • 予約語は使用できない

予約語というのは、言語の中で他の目的で既に使われている語を指す。
JavaScriptの場合、予約語には次のようなものがある。
break, case, catch, continue, default, delete, do, else, finally, for, function, if, in, instanceof, new, return, switch, this, throw, try, typeof, var, void, while, with

また、windowオブジェクトが持つプロパティも変数名として使わない方が良いとされている。
たとえば、nameなどがこれに含まれる。

変数名をつけるときは変数の意味を表すようにした方が、プログラムがわかりやすくなる。
例えば合計を格納する変数には「sum」という名前をつけたり、ニックネームを保存する変数には「nickname」という名前をつけたりすると良い。
ただし、あまり長くなりすぎるのも問題である。
適切に省略するようにすることが必要である。

変数の付け方には、いろいろな流儀がある。
たとえば、キャメルケースハンガリアン記法Google JavaScript Style等がある。
いろいろなサイトの例題を見ていると同じような流儀でプログラムが書かれているのに気づく。
必ずしもこのような流儀に則って変数名や関数名を決めなければいけないわけではないが、綺麗な読みやすいプログラムを書く助けになるので、参考にするとよい。

変数のスコープ

上記で変数宣言を行わない場合は問題を起こす場合が多いと述べた。
なにが問題なのだろうか?
多くのプログラミング言語には「スコープ」と呼ばれる概念がある。
これは、名前をある場所に限って使えるようにする、というものである。
例えば、「date」や「sum」といった一般的な名前の変数は、多くのプログラムで使われる可能性があるが、同姓同名の人がいると取り違えて混乱が起きるように、別のデータを同じ名前の変数に保存しようとすると、変な動きになってしまう。
そのため、名前が有効になる範囲をプログラムの一部分に限ってしまおうというのがスコープの考え方である。

次のプログラムではそのような混乱が起きる例を示している。
ここでalert()はメッセージをポップアップ表示するための関数である。
この例では、変数wordの中の値を表示している。

var word = "こんにちは";

// hello関数1
function hello1() {
var word = "こんばんは";
alert(word);
}

// hello関数2
function hello2() {
alert(word);
}

// hello関数3
function hello3() {
word= "こんばんは";
alert(word);
}

// hello関数4
function hello4() {
{
var word = "こんばんは";
}
alert(word);
}
<button onclick="hello1()">hello1</button>
<button onclick="hello2()">hello2</button>
<button onclick="hello3()">hello3</button>
<button onclick="hello4()">hello4</button>

実際の動きは下記のとおりである。
ボタンを押してみよう。
何が起きているだろうか?
ボタンを押す順序によっても動きが変わるので、ブラウザのリロード機能などを駆使して動きを把握してほしい。
デバッガを使うのも有効である。





hello1ボタンを押すと、「こんばんは」と表示される。
これは、6行目のalert()で表示されている。
表示内容は、すぐ上の5行目において宣言されている変数wordの値である。

初めに、hello2ボタンを押すと、「こんにちは」と表示される。
これは、11行目の文でアラートを出している。
値としては、1行目において初期化したものである。
ここで、5行目の代入文で代入された値が表示されていないことに注意して欲しい。
5行目の代入文が無関係なのはなぜだろう?
「プログラムは基本的に上から下へ実行されます」という規則に則ると、11行目のalert()より前に5行目の代入文があるので、wordの値は「こんばんは」になるはずである。
しかし、4行目から7行目までは関数宣言である。
この部分は宣言であって、実際に他から呼び出されるまでは実行されることはない。
そのため、変数wordの値は変更されることはない。
しかし、この説明だと、一度hello1ボタンを押したあとでhello2ボタンを押すと、「こんばんは」と表示されるはずである。
しかし実際には、たとえhello1ボタンを押した後にhello2ボタンを押しても「こんにちは」と表示される。
実は、このプログラムでは、1行目で宣言されているword変数と5行目で宣言されているword変数は別物なのである。
これがスコープである。

JavaScriptにはグローバルスコープとローカルスコープと呼ばれる2種類のスコープが存在する。
スコープというのは変数や関数を参照できる範囲を決めているもので、グローバルスコープの場合にはプログラムのどこからでも参照が可能である。
一方で、ローカルスコープの場合は、関数の中に閉じており、関数の中だけでしか参照することができない。
上の例では、1行目のword変数はグローバル変数(グローバルスコープの変数)として、5行目のword変数はローカル変数(hello2関数の中からのみ参照可能な変数)として定義されている。
このため、hello2関数の中からは1行目で宣言したword変数にはアクセスできるが、hello1の中のword変数にはアクセスできない。
逆にみると、hello1の中からword変数を参照するとローカル変数の方が参照され、グローバル変数にはアクセスできなくなっている。

ローカル変数の宣言は、関数のなかで「var」を使って宣言を行うことによって可能である。
関数外で宣言をした場合には、1行目の宣言のようにグローバル変数となる。
ややこしいのは、関数の中で「var」による宣言をしなかった場合には、その変数はグローバル変数として扱われるということである。

グローバル変数を使う場合は細心の注意が必要である。
たとえば、上記の例においてhello3ボタンを押した後に、hello2ボタンを押してみてほしい。
「こんばんは」と表示される。
これは、hello3()関数の中でグローバル変数であるword変数の中身を書き換えてしまったため、hello2()関数にも影響を与えている例である。
敢えてグローバル変数を使う場合には、他の変数と混同しないように変数の命名に気をつけるべきである。
このプログラムでは「word」という安易な名前を付けているが、このような安易な名前を使うと思いがけず他のところから参照してしまったり、別のプログラムと組み合わせて使う場合に名前の衝突を起こしてしまったりすることがある。

これまでC言語などの別の言語を学んだことがある人が陥りがちな罠が、hello4ボタンである。
JavaScriptには、グローバルスコープと関数局所スコープしかない。
このため、hello4()関数のように新しいブロックを作っても、関数内のローカル変数となりますので注意が必要である。
初めてプログラミングを学ぶ人は、このように新しいブロックを作ることで別のスコープを明示的に作ることができるプログラミング言語もあることを知っておいて欲しい。

プログラミング言語には「式」という概念がある。
数学で式というと、y=2x+3のようなものを思い浮かべるが、プログラミングにおける式の概念は少々異なっている。
プログラミングにおいての式は「評価(計算)をして値を生成するもの」である。
例えば、「1」も式だし「"hello, world"」も式である。
前者は1という数字を値として生成(という程でもないが)するし、後者は"hello, world"という文字列を値として生成する。

式を「評価する」という表現は耳慣れないかもしれない。
プログラムの場合には、式は必ずしも算術演算を行うものではない。
例えば、これまでみてきたように文字列を生成するものもあるし、「変数nは3より小さいかどうか」という条件に対してYes(真、true)またはNo(偽、false)の結果を出すものもある。
また、関数の場合には、値を生成しないものもある。
そこで「計算をする」とは言わず「評価する」と表現する。
実際には、変数や定数を使って、式や関数を実行し、その結果を得る事を指す。

式は演算子オペランドで成り立っている。
演算子とは+-など値を操作するための記号である。
また、オペランドは逆に演算子によって操作される対象ということになる。
例えば、「1+2」では、1や2はオペランドで+が演算子ということになる。
また、この式の評価結果は3となる。

JavaScriptに限らず、多くのプログラミング言語にはたくさんの演算子がある。
これらは、オペランドの数で分類することができる。
例えば+演算子ではその右と左にそれぞれ1つずつのオペランドを取る。
このことから2項演算子と呼ばれる。
また、1項演算子や3項演算子というものもある。
例えば負の数を表す「-3」などで使われる-記号は1項演算子である。

算術演算

基本的かつ理解しやすい式として、まずは算術演算をみてみる。
算術演算には例えば次のような演算子がある。

演算子 意味 使用例
+ 左右の値を足し合わせる 1+2、1024+2048
左の値から右の値を引く 5-3、2048-1024
* 左右の値を掛け合わせる 1*2、1024*2048
/ 左の値を右の値で割る 6/3、2024/128
% 左の値を右の値で割った時のあまりを求める 100%30、29%2
++ インクリメント(値を1加算する)。加算した値はオペランドで指定した変数に再設定される。 ++i、j++
−− デクリメント(値を1減算する)。加算した値はオペランドで指定した変数に再設定される。 −−i、j−−

+」「-」「*」「/」の4つの演算子については、普通の四則演算なので説明はいらないだろう。
%」は普段の生活の中ではあまり使わないかもしれないが、余りを返す演算である。
例えば100/30だと余りは10なので100%30という式は10を返す。
また、JavaScriptの「%」演算では、小数点以下も余りとしてそのまま残る。
例えば、100.5%30の結果は10.5となる。

++」や「−−」は更にわかりにくいかもしれない。
これは変数の中の値に働きかける演算子で、「++i」と書くとiの中の値が1増えてその値が返される。
たとえばiが5だったときに「++i」と書くと、返ってくる値は6で、しかもiの値自体が6に置き換わる。
さらにややこしいのは「++i」と記述したときと「i++」と記述したときで動きが違うことである。
++i」と記述した場合には先に値が1増えてからその値が返される。
しかし、「i++」と書いた場合には、値を増やす前の値が返されてから変数の中の値が1増える。
iの値が5の時に「++i」と書くと返される値もiの中身も共に6になるが、「i++」と書くと返される値は5なのに、iの値は6となる。
j=i++」のような式を記述して、ijの値を確認すると動作が理解できる。

文字列の演算

文字列にも演算子がある。
次に例を示す。

演算子 意味 使用例
+ 連結。左右の値を連結して1つの文字列を生成する。 "hello, " + "world""My name is" + firstname

文字列の演算の際には注意すべき事がある。
例えば「5+4+"3"」のように文字列と数字を混ぜて演算をした場合である。
+」演算子には算術的な加算の意味と、文字列の連結の意味がある。
5+4+"3"」のような場合には、左側から演算が評価されていくので括弧書きで表現すると「(5+4)+"3"」となる。
このため、始めに「5+4」が実行されて「9」になり、これが文字列である「"3"」と連結されるために文字列の「"9"」に変換され、最終的に「"93"」となる。
このように、数値型のオブジェクトは文字列が現れた時点で、自動的に文字に変換され、文字列の演算になりますので、注意が必要である。

代入演算子

これまでに述べてきた演算子とはちょっと毛色の違うものとして、代入演算子と呼ばれるものがある。
代入演算子は実はこれまでにも使ってきた。
変数に値を入れる代入文である。
実はJavaScriptの中では、値の代入に使った「=」も演算子の一種として扱われる。

また、代入演算子は、これまで変数に値を入れる為に使ってきた「=」以外にもある。
以下にまとめる。

演算子 意味 使用例
= 代入。右の値を左の変数に代入する。 a = 1、a = b、a = 3 + 4
+= 右の値を左の変数に足し込む。 a += 1、a += b、a += 3 + 4
-= 右の値を左の変数から引く。 a -= 1、a -= b、a -= 3 + 4
*= 右の値を左の変数に掛け、その結果を左辺に代入する。 a *= 1、a *= b、a *= 3 + 4
/= 右の値で左の変数を割り、その結果を左辺に代入する。 a /= 1、a /= b、a /= 3 + 4
%= 右の値で左の変数を割り、そのあまりを代入する。 a %= 1、a %= b、a %= 3 + 4

代入演算子を使う場合には、代入演算子の左辺はかならず変数となることに注意が必要である。

演算子の優先度

数学では、足し算や引き算よりかけ算や割り算の方が結合が強く、「1+2*3」の答えは9ではなく、7となる。
JavaScriptでもこれと同じ様な結合の強さの概念がある。
下記に結合の強さを示す。

結合の強さ 演算子
強い ( )
++、−−、−
*、/、%
+、−
弱い =、+=、-=、*=、/=、%=

例えば「a %= 3 + 4」は、aを7で割った余りがaに代入され、aを3で割ったあまりをaに代入した後、それに4を足したものが、式の値になるのではない。

上記からわかるように一番強い結合をもつのは「括弧()」である。
もし、結合の順番をかえたい場合は結合を強めたい部分を括弧でくくると良い。
必ずしも結合を強めたいような場合でなくとも、紛らわしい式を括弧をつかってわかりやすくする事は、プログラムのミスを防ぐ為に有効である。

文と宣言

JavaScriptのプログラムは、「文」と「宣言」で構成されている。
ここでは、簡単に「文」と「宣言」とは何かについて説明する。

」とは処理の基本単位であり、何らかの手続を表す。
また、手続きの流れを制御することもある。
JavaScriptにおいては、式文(式が1つの文として扱われるもの。多くの場合は代入演算子を伴う)、制御文(正確にはif文やbreakable文等に分類される)、return文等が存在する。
これらの文を組み合わせることによって、一連の手続きを記述することが可能となる。

宣言

「宣言」は、プログラムの他の部分から参照できるようにする手続きで、その部分が実行される(読み込まれる)ときにはなにも起きない。
実際にプログラムの他の部分から実行されるように指示があって初めて効力を発揮する。
関数宣言などがこれにあたる。

WebへのJavaScriptプログラムの組み込み

script要素とJavaScript

当然のことながら、HTML(Webページ)とJavaScriptのプログラムを結びつけるためには、何らかの仕組みが必要となる。
この目的で、HTMLには「script要素」が用意されている。
script要素はHTMLの中にプログラムを挿入する際に使われる要素である。
実際には次のような2つの書き方ができる。

script要素の中に直接プログラムを書く方法
...
<script type="text/javascript">
var a=1;
var b=2;
alert(a + "+" + b + " = " + 3);
</script>
...
script要素の属性にプログラムファイルへのパスを書く方法
...
<script type="text/javascript" src="example.js"></script>
...

前者の書き方はプログラムが短い場合、後者の書き方はプログラムの規模がある程度大きい場合に使いやすい。

もう1つ、JavaScriptの埋め込みとしては、後に述べるイベントハンドラがある。

JavaScriptが実行される仕組み

Webブラウザは、HTMLを読み込むと基本的には上から順に処理していく。
この際、処理している中にscript要素があると、そのタイミングでJavaScriptのプログラムが実行される。
ただし、宣言に関しては関数が定義されたりするだけで、実行されるのは別のタイミングである。
関数宣言の外側にあるプログラムに関しては、読み込まれたタイミングで実行されるということである。
また、JavaScriptからHTMLの要素を操作するような場合には、JavaScriptのプログラムが実行される時点で、HTMLの要素が出来ていなければならないことに注意が必要である。

ここで、script要素を何処にいれるか悩むかもしれない。
一般的には次の2つの方法のどちらかが採用される。
1つはhead要素の中にscript要素を入れるやり方、もう1つはbody要素の最後に入れるやり方である。

イベントモデル

HTMLとJavaScriptの連携の1つに、イベントハンドリングがある。
ここではWebページが発生させるイベントとそのハンドリング方法について説明する。

HTML要素とイベント

HTMLで表現されたページは、Webブラウザによって表示されるとWebブラウザによってイベントを発生する。
イベントは、ボタン等の要素に対するクリック(onclick)やダブルクリック(ondblclick)などユーザ操作によって発生するもの、ページの読み込み終了時や別のページに移動する時などに発生するものなどがある。
以下に、Webブラウザが発生させるイベントの種類を示す。

主なイベントの例を下記に示します。

タイプ イベント イベントの内容
ページ等 onload ページ等の読み込み完了した時
onunload 他のページへの移動時、ページのクローズ時
onresize サイズが変更された時
onscroll スクロールした時
マウス onclick クリックした時
ondblclick ダブルクリックした時
onmousedown マウスボタンを押した時
onmouseup マウスボタンを放した時
onmouseover マウスが重なった時
onmouseout マウスが離れたとき
キー onkeydown キーが押し下げられた時
onkeypress キー入力があった時
onkeyup 押し下げられたキーが放された時
フォーム onchange 内容が変更された時
onsubmit サブミットボタンが押された時
onreset リセットボタンが押された時
フォーカス onfocus フォーカスされた時
onblur フォーカスが外れた時

イベントによる関数の呼び出し

HTML+JavaScriptでは、イベントによってJavaScriptのプログラムを起動することが多い。
このようなイベントに対応づけられたプログラムのことを、イベントハンドラと呼ぶ。
多くの場合、JavaScriptのイベントハンドラは関数として定義されており、その関数を呼び出すことによってプログラムを実行する。

ボタンがクリックされると、アラートが表示されるHTMLとJavaScriptのプログラムを下記に示す。

HTML
...
<button onclick='message();'>Click me!</button>
...
JavaScript
function message() {
alert("ボタンが押されました");
}

上記のHTMLおよびプログラムによって次のようなボタンが実現できる。
実際に試して欲しい。


この JavaScriptのプログラムでは、1行目から3行目で「message」という名前の関数を宣言している。
関数の中身は2行目の1行だけしかなく、アラートを表示しているだけである。
また、HTMLの方では、「onclick」イベント発生時に「message()関数」の呼び出しを行うよう定義している。
つまり、「onclick」イベントにたいするイベントハンドラを定義している。

ここで、HTMLに記述するイベントハンドラはJavaScriptのプログラムそのものであることに注意して欲しい。
'message();'」の部分には、JavaScriptのプログラムを書くことができる。
そのため、直接「alert()関数」を呼び出すことも可能である。
このような例を次に示す。
この記述方法でも上記と同じような動作をするが、イベント発生時に複雑な処理を行うような場合は、関数を宣言してそれを呼び出したほうがプログラムが読みやすくなる。

HTMLの中のイベントハンドラにJavaScriptのプログラムを埋め込む場合
...
<button onclick='alert("ボタンが押されました");'>Click me!</button>
...

練習問題2-

script要素の中にプログラム(関数)を書いて、ボタンを押すと「こんにちは」とアラートで表示するプログラムを作成しなさい。


練習問題2-

外部のファイルにプログラムを書いて、それをscript要素で読み込む方法で、ボタンを押すと「こんにちは」とアラートで表示するプログラムを作成しなさい。

練習問題2-

「0にする」「1増やす」「1減らす」「2倍する」「1/2する」というボタンを作り、それぞれのボタンが押されるとその動作をして結果をアラートで表示するプログラムを作成しなさい。
ただし、値の初期値は0とする。