関数と引数、センサー

目標

これまでにもイベントが起きた時に実行されるイベントハンドラとして関数を扱ってきた。
ここでは、より複雑な関数について学ぶ。

  • 関数の概念について理解する。
  • 引数を使った関数の作成や、呼び出しができるようになる。
  • 他人が作った関数を呼び出せるようになる。
  • コールバック関数の概念について理解する。
  • センサー情報を取得するためのコールバック関数開発ができるようになる。

関数と引数

関数では、関数を呼び出す際に値を渡すことができる。
引数として関数に渡した値は、引数に記述した変数に代入されて、関数内で参照することができる。
この時、普通の変数を新しく定義する時のように、varはつけない。

JavaScript
function sum(num1, num2){
    alert(num1 + num2);
}

sum(20, 15);
// 35がアラート出力される

上の例では、5行目のsum()関数の呼び出しにより、20と15という数字がsum()関数にわたされる。
このような値のことを引数と呼ぶ。
実際のsum()関数は1行目から3行目で定義されている。
1行目の括弧の中には、num1およびnum2という変数が指定されている。
これは、関数呼び出しの際の引数を受けるための変数で、仮引数と呼ばれる。
関数は呼び出されると、仮引数で指定されている変数に値が入った状態で動作する。
つまり上の例では、2行目のalert()によって、num1+num2の計算結果、つまり35がアラートで表示されることとなる。

関数、仮引数、返り値の概念をより直感的にわかるように下記の図に示す。
左のプログラムの中の緑の部分が、右の関数に展開されるような形で実行される。
この例では、引数にか加えて返り値が導入されている。

関数呼び出し

この例では、add()という関数を定義して使っている。
add()という関数は、仮引数としてxとyの二つを持っている。
関数の中では、この二つの変数を足し算をして別の変数zに格納し、そのzをreturn文を使ってもとのプログラムに返している。
呼び出しもとのプログラムの方をみてみよう。
aという変数を定義して、それを2で初期化している。
その次の行では、変数sumを定義している。
次の代入文のところでadd()という関数が出てくる。
add()関数を呼び出すにあたって、引数に1という値とaという変数が指定されている。
関数を呼び出すと制御が一旦関数側に移るが、この際、引数に指定された値が関数の仮引数にセットされる。
この例の場合は、xに数値である1が、yにはaの中の値である2がセットさる。
このため、add()関数の中のz=x+yが実行されるときには、xが1、yが2になっており、zは3となる。
その後、add()関数の中の最後の行であるreturn文によって、関数が最終的に呼び出し側のプログラムに返す値がzであることが示されている。
この値のことを返り値と呼ぶ。
このため、呼び出し側ではadd(1, a)の評価結果は3となり、結果として変数sumに3が代入される。

JavaScript
// add()関数の定義
function add(x, y) {
    var z = x + y;
    return z;
}

// 呼び出し側のプログラム
function lec01_02_click() {
    var a = 2;
    var sum;

    sum = add(1, a);

    alert('sum = ' + sum);
}

コールバック関数

JavaScriptはすべての値は「オブジェクト」として表現されるため、どんなものでも同じ変数の中にいれることができる。
そのため、関数を呼び出す際に関数も引数として渡すことができる。
このことを活用して、関数を引数として登録しておき、処理が終わった、センサーの値が変わったなどの何らかのイベントでその関数が呼び出されるような仕組みを実現することができる。
このようなイベントに備えて登録される関数を、コールバック関数(callback function)と呼ぶ。
具体的な例については、次章以降のセンサーの使い方の部分を参照してほしい。

Ambient Light Events

World Wide Webコンソーシアム(W3C)のDevice APIs Working Groupでは、多くのセンサー情報を使うためのAPIを標準化している。
その中に、iMacでも使えるものとして照度センサーがある。
ここで使ってみよう。

次のプログラムを見てほしい。
HTML部では、テキストエリアを作成し、その後ろに「lux」という単位を表示している。
luxは照度を表す単位である。
JavaScript部では、始めにlight_print()という関数を定義している。
この関数は、照度に変化があった時に呼び出されるコールバック関数である。
照度が変化した時に呼び出される関数は1つの引数を取ることがAPIで決められているため、その引数を仮引数eventで受けている。
2行目から3行目はそれぞれ、テキストエリアを取得し、そのテキストエリアに実際の照度の値を設定している。
6行目はプログラムが読み込まれたときに実行される部分である。
ここで、'devicelight'は照度センサーを表している。
照度センサーの値に変化があると、第2引数で設定されている関数であるlight_print()が呼び出される。
1度設定しておくと、値に変化があるたびにこの関数が呼び出されることに注意してほしい。

HTML
<input type="text" id="lighttext" value="照度を変化させてくだい"> lux
JavaScript
function light_print(event) {
	var elm = document.getElementById('lighttext');
	elm.value = event.value;
}

window.addEventListener('devicelight', light_print);
表示例
lux

iMacの照度センサーはカメラの横にある。
カメラの部分に手をかざしたり、離したりすると照度センサーの検知する値が変化する。

最近のFirefoxで照度センサーを使うためには、
ブラウザで「about:config」を開き(アドレスバーに「about:config」と入力してください。警告が出る場合ありますが、そのまま進んでください。)、
device.sensors.ambientLight.enabled の値を true にする必要があります。
値を true にするためにはdevice.sensors.ambientLight.enabledの行をダブルクリックしてください。
JavaScriptにおけるセンサー情報の利用はまだまだ発展途上段階です。
多くのスマートフォンでは既にサポートしていたりしますが、固定のPCではたとえセンサーを内蔵していても、JavaScriptからは使えないことも多いようです。
また、ブラウザによっても使える機能が異なったりします。
実際、照度センサーはFirefoxでは使えますが、Mac OS XのSafariでは使えません。

タイマー

センサー情報等を使いはじめると、定期的に処理したくなることがある。
ここでは、JavaScriptにおけるタイマーの使い方について学ぶ。

JavaScriptでは、指定時間後に指定した関数を呼び出すタイプのタイマーと、定期的に指定した関数を呼び出すタイプのタイマーの2種類が使える。
前者は、1回関数が呼び出されると、それで終了となる。
後者は、例えば3秒毎に何度でも繰り返し関数が呼び出されることとなる。

次のプログラムを見て欲しい。
このプログラムでは、始めにtimeout_callback()というコールバック関数を定義している。
この関数が呼び出されるとアラートが表示される。
また、5行目では10000ms後(10秒後)にtimeout_callback()を呼び出すように設定している。
このため、このプログラムを実行すると、10秒後に「timeout!」と書かれたアラームが表示される。

JavaScript
function timeout_callback() {
  alert("timeout!");
}

setTimeout(timeout_callback,10000);

また、似たプログラムだが、次のプログラムはすこし違う動作をする。
上のプログラムとの違いは、5行目がsetTimeout()ではなく、setInterval()になっているところのみである。
こちらのプログラムでは、上と異なり、10秒毎にtimeout_callback()が呼び出され、結果的に10秒毎にアラートが表示される。

JavaScript
function timeout_callback() {
  alert("timeout!");
}

setInterval(timeout_callback,10000);

また、繰り返し呼び出されるタイマーを、開始したり停止したりするためには、タイマーを指定する必要がある。
setTimeout()関数やsetInterval()関数は呼び出されるとタイマーオブジェクトを返すので、それを変数に記憶しておくことにより、
タイマーを停止させたりすることができる。

次のプログラムでは、setInterval()が返す値を変数timerに記憶しておくことによって、
タイマーを開始したり止めたりすることができるようになっている。
setInterval()の中にあるtimeout_callbackは、タイムアウトした時に呼び出される関数の名前である。

HTML
<button onclick="startTimer()">Start</button>
<button onclick="stopTimer()">Stop</button>
JavaScript
var timer = null;

function startTimer() {
    if (timer == null)
        timer = setInterval(timeout_callback, 3000);
}

function stopTimer() {
    if (timer != null)
        clearInterval(timer);
    timer = null;
}

練習問題9-

次のように、曜日と時限を引数として呼び出すと、その時間帯に履修している科目名が返るような関数を作成しなさい。
ただし、何も履修していない曜日時限が入力された場合は、「履修している科目はありません。」と返すものとする。

...
var week = "mon";
var period = 1;
var title = classTitle(week, period);
...

また、2つのテキストエリアと1つのボタンをつくり、それぞれのテキストエリアに曜日と時限を入力してボタンを押すと、
作成した関数を使って履修している科目名を取得し、その科目名をアラートで表示するようなページを完成させなさい。

ヒント: 関数側にデータをもたせます。

練習問題9-

上の例で示した、照度の変化によって下記のように照度の値が変化するWebページを作成しなさい。

lux

練習問題9-

次のように照度が変化すると棒グラフが動くようなプログラムを作成しなさい。

棒グラフ

練習問題9-

スタートボタンを押してから10秒後に1回だけ「timeout!」とアラートで表示するプログラムを作成しなさい。

練習問題9-

スタートボタンを押してからから10秒毎に「timeout!」とアラートで表示するプログラムを、setInterval()を使って作成しなさい。
また、ストップボタンを押すと止まるようにしなさい。

練習問題9-

テキストエリアから文字列を入力してボタンを押すと、その文字列をページ内に予め用意したp要素内に1秒ごとに1文字ずつ表示するプログラムを作成しなさい。
例えば、テキストエリアに「keio」と入力されてボタンが押された場合、
1秒目に「k」、2秒目に「ke」、3秒目に「kei」、4秒目に「keio」とp要素に表示される。

ヒント: 文字列のn文字目を取り出すためには、charAt()を使います。使い方は自分で調べてみましょう。

練習問題9-

次のような、照度センサーの値を示した棒グラフが1秒ごとに横に流れていくプログラムを作成しなさい。

棒グラフ