JavaScript応用編
オブジェクト
基礎編のページでは,特に断りなくオブジェクト(Object)という単語を用いていた.
JavaScriptはオブジェクト指向言語であり,変数に代入できるものはほぼ全てがオブジェクト,という特徴がある.(undefinedなどの特殊な値や,true/falseなどのプリミティブ値はオブジェクトではない)
「オブジェクト」は数値や文字列のように分かりやすいものではなく,定義が難しいが,さしあたっては
- プロパティ(property)
- メソッド(method)
を持つもの,と覚えておけばOK.(HTML基礎編のページにも書いたように,C言語の範囲内の知識だと「構造体を拡張したもの」に近い)
JavaScriptにおけるオブジェクト実装例
以下では,具体例で説明する.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
このHTMLをブラウザに読み込ませると,\(^^)/
というキャラクター?が表示され,左右の矢印キーを押すとウィンドウ上を動くはずである.
以下,このプログラムを少しずつ解説する.
Bodyタグのonload属性
この属性が指定されると,HTML文書の読み込みが終わったときに,指定された関数が実行される.今回の場合はinit()
関数が実行される.
14 15 16 17 |
|
15行目でkeydownイベントに対するハンドラを登録している.つまり,キーが押される度にcallback_keydown
関数が実行されるようになる.
16行目が,実際にオブジェクトを生成している部分である.以下ではさらに細かく見る.
オブジェクトの作り方
JavaScriptでは
オブジェクト = new 関数(引数1, 引数2, ...) {
...
}
という形でオブジェクトを作る.関数定義と間違いやすいが,こちらにはキーワードnewがついている.オブジェクトを生成する関数のことを特に「コンストラクタ」(constructor)と呼ぶ.コンストラクタは,他の言語では分かりやすく(普通の関数とは)区別されていることが多いが,JavaScriptでは区別されていないので注意.
この16行目で,chara
という名前のオブジェクトが生成され,(そのオブジェクトを操作するための)メソッドを呼び出せるようになる.今回の場合,charaにはmoveLeft
とmoveRight
というメソッドが(定義・)実装されているので,これらを呼び出すことができる.
メソッドの呼び出し
オブジェクトのメソッドを呼び出すには
オブジェクト.メソッド();
のように,ピリオド(.
)をつける.charaオブジェクトのmoveLeftメソッドを呼ぶにはchara.moveLeft()
と書く.18行目からのcallback_keydown関数を見ると
18 19 20 21 22 23 24 25 |
|
となっており,押されたキーが左矢印(キーコード37)ならchara.moveLeft()を呼び,右矢印(キーコード39)ならchara.moveRight()を呼び出している.
このプロパティ呼び出しの際,呼び出した側(オブジェクトを使う・利用する側)は実際にcharaオブジェクト内で何が起きているかを知る必要はなく,ただ結果としてcharaが右なり左なりに動いてくれれば良いだけ,である.この考え方がオブジェクト指向プログラミングの特徴.
オブジェクトの宣言(定義)
さて,ではオブジェクトを提供する側のプログラムも見ていこう.
26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
プログラム中のthis
は,「オブジェクト自分自身」を表す(他言語ではself
などというキーワードになっていることもある).16行目の
16 |
|
という命令でchara
オブジェクトが作成されるが,この第1引数はDOM(Document Object Model)要素,第2引数はウィンドウ上のx座標値である.
27行目で,第1引数であるelementをthis.element
に代入しており,これによってオブジェクト自身のelement
プロパティに「<div id="chara">\(^^)/</div>
」というDOM(Document Object Model)要素(への参照)が格納されることになる.同様に,28行目ではオブジェクトにxpos
というプロパティを登録し(てその初期値を第2引数で受け取ったxposにし)ている.このように,オブジェクトには自由にプロパティを追加することができる.
29行目以降はメソッドの定義部分である.
29 30 31 32 |
|
functionに名前がついていないが,JavaScriptではこのような無名(匿名)関数が利用できる.ここでは,moveLeft
というプロパティに無名関数が代入されることでメソッドが実現されている.関数の中では,element(DOM)要素(this.element)のleftスタイルの値(style.left)を更新して表示場所を変更しているだけである.ここで,「style.left」は左端からの距離を表している.
class構文を用いた書き方
上記のプログラムは class構文を用いて書くこともできる.class構文を利用して書くと以下のようになる.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>オプジェクト実装サンプル(class構文)</title>
<style>
div {
position: absolute;
top: 50px;
}
</style>
<script>
function init() {
window.addEventListener("keydown", callback_keydown);
chara = new Character(document.getElementById("chara"), 100);
}
function callback_keydown(event) {
if(event.keyCode == 37) { // Left-arrow key
chara.moveLeft();
}
else if (event.keyCode == 39) { // Right-arrow key
chara.moveRight();
}
}
class Character {
constructor(element, xpos) {
this.element = element;
this.xpos = xpos;
this.element.style.left = this.xpos + "px";
}
moveLeft() {
this.xpos -= 10;
this.element.style.left = this.xpos + "px";
}
moveRight() {
this.xpos += 10;
this.element.style.left = this.xpos + "px";
}
}
</script>
</head>
<body onload="init()">
<div id="chara">\(^^)/</div>
</body>
</html>
組み込みオブジェクト
JavaScriptには,最初から用意されている便利な関数やオブジェクトがある.
タイマー
文字通りのタイマー機能.一定時間後に関数を実行したり,定期的に(一定間隔で)関数を実行したりできる.
メソッド | 機能 |
---|---|
setTimeout(関数名,ミリ秒) |
ミリ秒後に関数を1回だけ呼び出す |
clearTimeout(timerId1) |
setTimeoutの処理を停止する.timerId1 はsetTimeoutの戻り値 |
setInterval(関数名,ミリ秒) |
ミリ秒間隔で関数を定期的に呼び出す |
clearInterval(timerId2) |
setIntervalの処理を停止する.timerId2 はsetIntervalの戻り値 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Math
各種計算を行うためのメソッドを提供している.
メソッド | 機能 |
---|---|
Math.min(a, b) |
aとbの小さい方を返す |
Math.max(a, b) |
aとbの大きい方を返す |
Math.random() |
0以上1未満の乱数を返す |
Math.floor(n) |
nを切り捨てた整数値を返す |
Math.ceil(n) |
nを切り上げた整数値を返す |
Math.round(n) |
nを四捨五入した整数値を返す |
Math.sqrt(n) |
nの平方根を返す |
Math.PI |
円周率(3.1415926535... )を返す |
Array
基礎編のページに記載した「配列」は,実はArrayオブジェクト.
関数
JavaScriptの関数は「第一級オブジェクト」であり,通常のオブジェクトと同じ振る舞いが可能である.
第一級オブジェクト
あるプログラミング言語において、たとえば生成、代入、演算、(引数・戻り値としての)受け渡しといったその言語における基本的な操作を制限なしに使用できる対象のこと
// 関数宣言
function func1(a, b) {
// 省略
}
// 変数に代入して呼び出し
var f = function() {
console.log('f is called.');
}
f(); // 'f is called.'
// パラメータ的な使い方
var f2 = function() {
console.log('f2 is called.');
}
function func2(func) {
func();
}
func2(f); // 'f is called.'
func2(f2); // 'f2 is called.'
さらに,関数は「通常のオブジェクトと同様に扱える」ので,関数自身にも固有のプロパティやメソッドを動的に追加できる.
var myFunc = function() {
// 省略
}
// この時点ではプロパティiは存在しない
console.log(myFunc.i); // undefined
// プロパティiを追加
myFunc.i = 'Software Design';
console.log(myFunc.i); // 'Software Design'
また,通常のオブジェクトには無い,関数だけの特徴として,カッコ演算子で処理を呼び出せるというものがある.カッコ演算子をつけずに呼び出すと,自身の定義内容が参照される.
var f = function() {
return 'csd';
}
console.log(f()); // 'csd'
console.log(f); // '[Function: f]'
関数の引数
他の言語が「関数の定義通りに引数を渡さないとエラーになる」ことに対し,JavaScriptでは引数チェックが一切行われない.つまり,定義済み引数の個数より多く渡しても少なく渡しても,また,個々の引数の型が違っていたとしても動作する.グループ開発する際は十分に注意しよう.
function func(a, b, c) {
console.log(a, b, c);
}
// 少なく渡す
func('a'); // 'a undefined undefined'
// 多く渡す
func('a', 'b', 'c', 'd'); // 'a b c'
// 渡さない
func(); // 'undefined undefined undefined'
無名関数
JavaScriptでは,関数名が必要なければ省略することができる.この名前の無い関数を無名関数という.無名関数は,イベントハンドラやコールバックのように「複数回呼び出すことがない関数」を定義する際によく利用される.
// イベントハンドラで
window.onload = function () {
// 略
}
// コールバックで
setTimeout( function() = {
// 略
}, 1000);
window.onload で指定した関数は,windowオブジェクトが読み込まれたタイミングで実行される.setTimeout(arg1, arg2)では,arg2で指定した時間後に,arg1で指定した処理が実行される.
コールバック
引数として渡される関数のことをコールバック(またはコールバック関数)とよぶ.引数として渡すことで,何らかの任意のタイミングで関数を実行させられる.(代表的な用途としては非同期処理の実装)
function func(callback) {
console.log('func');
callback();
}
// コールバック
func( function() {
console.log('aaa'); // func aaa という順で出力
});
// コールバック
func( function() {
console.log('bbb'); // func bbb という順で出力
});
JavaScriptを使う場合,このような「任意のタイミングで実行したい処理(関数)を,引数として渡す」ということが当たり前に考えられるようになる必要がある.(イベントハンドラは,まさにこの考え方)
即時関数
JavaScriptでは,関数を定義すると同時に実行することができる.これを即時関数,あるいは即時呼び出しという.
無名関数を定義し,そのまま即実行することで,グローバルスコープを汚すこと(不要なプロパティの追加とか)を防げる.
// 基本的な使い方
(function() {
console.log('software');
}()); // <- この行の()によって無名関数が実行される,ということ.softwareと表示される
// 引数の渡し方
(function(a,b) {
console.log(a + b);
}('software','design')); // softwaredesign
即時関数は「全体をカッコで括る」必要があるので注意すること.