第3回目になる、Ext JS開発ガイドです。今回は、「モダンJavaScript」について学んでいきます。
モダンJavaScript
モダンJavaScriptといっても、言語的に変わったとかそういう話ではありません。現代風JavaScriptの書き方について学んでいきます。
私は、最近よくExt JSを人に教えたり、コンサルティングや提案などで説明する機会があります。そこで、技術者の方を話をしていると、どうも話がかみ合わない場面があります。
それは、JavaScriptに関する誤解です。
たいがいJavaScriptは、「alert表示するものでしょ?簡単な入力チェックに使うものでしょ?どうせサーバサイドでも入力チェックしなくちゃいけないんだし。」と思っている技術者の方も、まだ相当数いるようです。
わざわざこの記事を書いているのは、「そうではありません」というためです。
では、どう違うのでしょうか?
それは、知識の曖昧さから生まれている誤解だと思います。
そのJavaScriptに関する知識を一つ一つ確認していきながら、みていってください。
また、Ext JSを利用した開発では、JavaScritp以外に先に学んだCSSの基本的な知識が必要です。CSSに関してもJavaScript同様、きちんとした基礎知識があるかないかで、JavaScriptのコードにも影響を及ぼします。
JavaScript基礎確認
さて、では早速、次のJavaScriptの基礎知識を確認してきます。
大文字と小文字の区別
JavaScriptは、大文字・小文字を区別して動作します。次のコードをみてください。
var foo = ‘A’;
var Foo = ‘B’;
var FOO = ‘C’;alert(Foo);
最後にalertでメッセージを表示しています。このときに引数に渡している変数Fooの値は、「B」になります。他のfooもFOOも大文字・小文字が違うため別な変数として認識します。
セミコロン
通常、区切りにセミコロン(;)をつけますが、JavaScriptでは、文末にセミコロンを省略できます。しかし、セミコロンをつけないせいでデバッグが困難になる場合があります。
var foo = ‘A’
var Foo = ‘B’;alert(Foo);
変数fooの定義している文末にセミコロンがありませんが、上記のコードは動作します。しかし、リスク回避のためにも、文末にはセミコロンをつける癖をつけましょう。
var foo = ‘A’;
var Foo = ‘B’;alert(Foo);
コメント
JavaScriptのコメントは、CやC++のようなコメントスタイルをサポートしています。
行コメント
// コメント行です。
ブロックコメント
/*
ブロックコメントです。
*/
ドキュメンテーションコメント
/**で始まるコメントは、JSDocを使えば、ドキュメンテーションコメントとして解析されます。
JSDocはJavaDocのような感覚で、JavaScriptのクラスを、下記のようなコメントにより定義することができ、コードとドキュメンテーションは同期することが出来ます。
/**
* サンプルメソッド
*
* @param {String} display (オプション) サンプル値
* @param {Integer} myVar (オプション) 他の値
* @return {String} ‘example’
*/
someExampleFunction : function(display, myVar){return ‘example’;
}
参照:http://jsdoc.sourceforge.net/
予約語
以下の予約語は、JavaScriptにおける変数と関数名として予約語の使用を避けてください。
- abstract
- boolean
- break
- byte
- case
- catch
- char
- class
- comment
- const
- continue
- debugger
- default
- delete
- do
- double
- else
- enum
- export
- extends
- false
- final
- finally
- float
- for
- function
- goto
- if
- implements
- import
- in
- instanceof
- int
- interface
- label
- long
- native
- new
- null
- package
- private
- protected
- public
- return
- short
- static
- super
- switch
- synchronized
- this
- throw
- throws
- transient
- true
- try
- typeof
- var
- void
- volatile
- while
- with
数値型
数値型は、次の値を扱うことのできる型です。
- 整数
- 16進数と8進数
- 浮動小数点(小数)
“+”が足し算、”*”はかけ算、”/”は割り算、、”-“は引き算、”&”はビット演算です。
また、JavaScriptのMathライブラリには多くの役に立つメソッドがあります。
- Math.abs(num)
- Math.sin(num)
- Math.ceil(num)
文字列
0文字以上のシングル、またはダブルコーテーションで囲まれた文字は、「文字列」として扱われます。
- “”
- ‘hoge’
- “foo”
- “This is a longer string”
エスケープシーケンス
文字列の中で、改行文字や復帰文字のように、バックスラッシュを含む文字は特別な意味を持ちます。
- ¥’
- ¥r
- ¥n
- ¥t
var myVar = ‘文字列\n文字列’;
alert(myVar);
上記のコードは、alertでメッセージを表示していますが、間にエスケープシーケンスを入れることで改行を表現できます。
文字列の追加
文字列の追加は、非常に単純です。
var anotherString = ‘new’;
var newVariable = ‘Something ‘ + anotherString;alert(newVariable);
数値型の値を加えるとき、自動的にストリングに変換されます。
var x = 12;
var newString = x + ‘ dozen eggs’;alert(newString);
文字列と数値
文字列から数値を抽出ために、数値変換することができます。
- parseInt
- parseFloat
var x = ’12’;
var y = ‘3’;alert(x+y);
var xNum = parseInt(x);
var yNum = parseInt(y);alert(xNum+yNum);
論理演算型
if文などの判定でtrue/falseを使うことがあると思いますが、次の一覧は、全てtrueと判定される例です。
- 1
- {}
- ‘ ‘ – space
- ‘my String’
逆に、次の例は、全てfalseとして判定されます。
- undefined
- null
- 0
- “”
オブジェクト
JavaScriptのオブジェクトとは次の特徴を持ちます。
- キーと値のペアの集合です。
- 無限に深く入れ子にすることができます。
- 連想配列かハッシュマップを提供します。
オブジェクトの作り方は、次のような方法があります。
Objectコンストラクタ
var newObj = new Object();
newObj.x = 10;
newObj.y = 20;
リテラル構文(JSON)
var newObj = {x: 10, y: 20};
関数
functionもまたデータ型の一つです。
var myFunc = function() {
alert(“hello”)
};
または、
function myFunc() {
alert(“hello”);
}
のように定義します。
上記は同じ機能を定義した関数ですが、定義方法が異なります。functionにもコンストラクタが存在しますが、グローバルスコープに関数を作成することしかできません。 グローバルスコープとは、windowオブジェクトのことを指します。
配列
配列の定義は、次の2つの方法があります。
Arrayコンストラクタ
var myArray = new Array();
myArray[0] = 12;
myArray[1] = 232;
配列リテラル構文
var myArray = [12,232];
配列の特徴は次の通りです。
- 配列を無限に入れ子にすることができます。
- 配列の要素が0個である場合があります。
- 配列は異なるデータ型を格納されることができます。
- 配列にも多くの役に立つメソッドやプロパティがあります。
また、配列自体に便利なメソッドやプロパティが用意されています。
- length : 配列の要素数を取得できるプロパティ
- push : 配列の最後に要素を追加するメソッド
- pop : 配列の最後の要素を取得、さらにその要素を配列から削除するメソッド
var myArray = [ 12, 232 ];
alert(myArray.length);
オブジェクトリテラル
オブジェクトリテラルは、JSON構文と一致しているのでオブジェクトを作成することに適しています。オブジェクトリテラルを利用するとき、キーと値のペアはコロンによって分離されます。
var newObj = {
x: 10,
y: 20,
myAry: [‘one’,’two’,’three’],
myFnc: function() {
return ‘A’;
}
};
オブジェクトプロパティ
参照方法は2つあります。
一つは、. (ドット)を使い、プロパティ名を参照する方法、もう一つは、ブランケットを利用してプロパティ名を指定し参照する方法です。
var obj = {
one:1,
two:2,
three:3
};alert( obj.one );
alert( obj[‘one’] );
上記のコードは、同じプロパティを参照しています。それぞれ.(ドット)とブランケットを利用した方法です。
nullとundefined
定義、曖昧じゃないですか?これら2つは同じではありません。
- nullは値を全く示さない特別なキーワードです。
- undefined宣言だけして値を割り当てたことがないか、参照したプロパティが宣言されていない状態であるものです。
これら、nullとundefinedは、両方ともfalseとして判定されます。
比較演算
変数を比較するために、比較演算子があります。
- == イコール – 値が同じかどうか
- != ノットイコール – 値が異なるかどうか
- > 大なり – 左辺の変数の方が大きいか
- < 小なり – 左辺の変数の方が小さいか
- >= 大なりイコール – 左辺の変数の方が大きいか、または同じ
- <= 小なりイコール – 左辺の変数の方が小さいか、または同じ
また、型を厳密にチェックする演算子として、次のような書き方ができます。
- === 厳密なイコール 型まで値が同じかどうか
- !== 厳密なノットイコール 型まで値が異なるかどうか
PHPなどのスクリプト言語には、結構こういった厳密な判定をするための比較演算子が用意されています。ケースバイケースで、しっかりとして判定を行いましょう。
論理演算
- && AND
- || OR
- ! NOT
論理演算子は、次の2つの使い方があります。
1つは、式の評価に使用します。
if (6 < 7 && 6 > 5) {
// some code.
}
もう一つは、変数に値を設定する場合に使用します。
var myObj;
myObj = existingObj || {};
existingObjがnullまたはundefinedの場合、{}がmyObjに代入されます。これは引数を受け取り初期値を設定するときなど、Ext JSのコード内でも多様されている記述方法です。
インクリメントとデクリメント
インクリメントは、+1するため、デクリメントは-1するために存在します。
var i = 6;
if( i == 6 ) {
alert( ‘6です。’ );
}
alert( i );
上記のコードをみてください。if文の中を処理するのがおわかりでしょうか。では、これにインクリメントを行ってみます。
var i = 6;
if( i++ == 6 ) {
alert( ‘6です。’ );
}
alert( i );
これは、どうでしょう。
実行すると、先ほどと同じくif文は、通過しますが、最後のalertは7になっています。iに+1されたことがわかります。
では、さらに次のコードはどうでしょうか。
var i = 6;
if( ++i == 6 ) {
alert( ‘6です。’ );
}
alert( i );
今度は、if文の中が処理されません。しかし、最後のalertは同じく7になっています。確かに+1されてますが、if文の判定では6としてiは評価されていません。
これは、先にインクリメント、またはデクリメントを記述すると、式の評価の前にインクリメント、デクリメントを行い、その結果が評価されます。つまり、最後の例では、iに+1されてから6と等しいかが判定されているため、if文の中が処理されないわけです。
インクリメント、デクリメントは単純に+1、-1するだけでなく、このように式の評価順に影響しますので、違いをしっかり押さえておきましょう。
new演算子
new演算子は新たにオブジェクトを生成するための機能です。また、コンストラクタは引数を持つことが出来ます。
var x = new Object();
var y = new Person(‘foo’);
var z = new Array();
ここで、new演算子を使用して、オブジェクトを生成できるのは、関数ですつまり、関数の処理自体がコンストラクタの役目を担います。
function myFunc( msg ) {
alert( msg );
}var obj = new myFunc( ‘hello’ );
カンマ演算子
カンマ演算子を使用すると、一度に複数の変数を宣言することができます。
var myObj = {}, myVar, myAry = [];
delete演算子
delete演算子を使用すると、オブジェクトから対象のものを削除することができます。
var obj = {
one: 1,
two: 2,
three: 3
};alert( obj.one );
delete obj.one;
alert( obj.one );
ifステートメント
if文は、式がtrueの場合に中の処理を実行します。
if(true) {
// 処理
}
上記の場合だと、式はtrueになります。trueはtrueなので処理が実行されます。
式には、先ほど登場した比較演算子、論理演算子が利用できます。
var i= 0
if( i == 5 ) {// 処理
}
if( i == 5 || i == 0 ) {
// 処理
}
一つ目のif文は、iが5であれば処理が実行されます。比較演算子ですね。
二つ目のif文には論理演算子||が設定されていて、iが5または0の場合に処理が実行されます。
var i = 2;
if ( i == 5 ) {// 処理1
} else {// 処理2
}
次の場合、iは2ですので、elseの中が実行されます。else文を使うと、ifで判定結果がtrueにならなかった処理を記述することができます。
さらに、else if文を使うと、if文での条件分岐を複数設定することができます。
var i = 5;
if (i==2) {
// 処理1
} else if (i==5) {
// 処理2
} else {
// 処理3
}
上記の例だと、iは5ですので処理2が実行されます。
forステートメント
for文を使用すると繰り返し処理が実行できます。
for (var i=0; i<10; i++) {
// 処理
}
上記の例では、10回の繰り返しを行うため、処理は10回行われます。
for文の構造は;(セミコロン)で区切られ、3つのセクションはそれぞれ次の処理が行われます。
- 初期化
- 評価
- 繰り返し後処理
初期化は、繰り返し処理が行われる最初に1度だけ実行されます。次に、式の評価が行われます。上記の例だとiが10より小さい値であるか?を判定します。この条件式がtrueの間繰り返し処理を行います。最後に、for文の中の処理が行われたあと、繰り返し後処理が行われます。
つまり、iが10になったあと評価が行われると、結果はfalseになるため、繰り返し処理から抜け出します。
また、for文は、for~inという形で記述することができます。
var obj = {one:1,two:2,three:3};
for ( prop in obj) {
alert( prop + ‘=’+ obj[ prop ] );
}
for~inは、上記のようにオブジェクトの内要素の数だけ繰り返す場合に使用します。inで区切られた最初にプロパティ名を格納する変数名を設定します。後ろには、走査するオブジェクトを設定します。
つまり、objにはone,two,threeという名前のプロパティにそれぞれ値が設定されています。なので、一つずつ繰り返されるたびにpropにはプロパティ名(one,two,three)が格納されます。propは変数なので、.(ドット)でオブジェクトを参照できないため、ブランケットを利用して値を参照します。
switchステートメント
switch文は、条件により処理を分岐させることができます。if~else if文に似ていますが、breakの使い方によっては、if~else ifでは表現できない記述も行うことができます。
var e = 11;
switch (e) {
case 10:
// 処理1
break;
case 11:
// 処理2
break;
default:
// デフォルト処理
}
eの値によりそれぞれの処理をcaseキーワードで定義します。eの値が、どのケースにも相当しない場合は、defaultで定義されている処理が実行されます。
breakキーワードを記述することで、switch文を抜け出します。記述しない場合は、次のcase文も実行します。
var e = 10;
switch (e) {case 10:
// 処理1
case 11:
// 処理2
break;
default:
// デフォルト処理
}
上記の場合、case 10:が処理されたあと、breakが無いため、そのままcase 11の処理が実行されます。
例外操作
tryキーワードを使うことで、エラーを起こすかもしれないコードを、エラーが発生してもブラウザには通知せずに実行することができます。
try {
// 処理
}
catch (e) {// 例外オブジェクトeが渡されます。
}
throwキーワードを使用して、カスタムエラーをブラウザに通知することができます。
try {
// 処理
}
catch (e) {throw new Error(‘カスタムエラー!’);
}
JavaやC#、PHPなどの例外を備える言語と同じように例外処理が行えます。
データ型
数値型、論理型(boolean)、null、undefinedに関しては、固定サイズのメモリ領域が確保されます。反対に、オブジェクト、配列、関数、クラスは、実行時に動的に割り当てられるメモリ領域のポインタになります。
つまり、配列を例にすると、定義したときの変数は、実際の配列値へのポインタであるといえます。
日付型
JavaScriptが実装している日付型は、他の言語の日付型に比べて制限があります。
Ext JSは、Dateオブジェクトのコンストラクタを拡張して、PHPの日付型相当の機能を提供しています。
詳しくは、API Documentationを参照してください。
変数の型
JavaScriptは、ColdFusionやPHPと同様に非タイプ型の言語です。
つまり、型宣言をしません。
実行時に、変数に関するデータ型を適時変更します。
変数の宣言
変数は、使用する前にvar使って宣言しなければなりません。
varをつけないで変数を割り当てると、グローバルな名前空間に作成されます。
さらに、その変数に値を割り当てないで読もうとすると、エラーになります。
変数のスコープ
varで宣言した変数後、どこに作られるかという話です。先ほどの宣言で、グローバルな名前空間に作成されるというのは、windowオブジェクト下に作成されることを指します。
var scope = “グローバル”;
function checkscope() {
var scope = “ローカル”;
alert( scope );alert( this.scope );
}
checkscope();
alert( scope );
alert( window.scope );
checkscope関数内で宣言されたscope変数は、”ローカル”という文字列が格納されています。なので、alertの引数に設定した、scope変数は”ローカル”という文字列が格納されているため、画面に”ローカル”と表示されますが、this.scopeとした場合、”グローバル”と表示されます。これは、checkscope関数が実行されたときのスコープがグローバルスコープになっているためです。
グローバルオブジェクト
先ほどから、グローバルな名前空間とか、windowオブジェクトとか出てきていますが、JavaScriptインタプリタが起動するたびにグローバルなオブジェクトが作成されます。ブラウザでは、グローバルなオブジェクトは”window”の名前を持っています。すべてのオブジェクトは、このwindowオブジェクトの下に生成されます。
ブロックスコープ
JavaScriptは、ブロックスコープがありません。そのため、ループ内で宣言された変数はローカル変数ではありません。
var len = 5;
for (var i=0; i<=len; i++) {
// 処理
}
alert(i);
alert(window.i);
ガベージコレクション
JavaScriptはJavaとC#と同様に、不必要なメモリを解放することが出来ます。この処理は「ガーベージコレクション」と呼ばれます。
オブジェクトが不要なときにJavaScriptインタプリタによって自動的に削除されます。正常に削除されない現象をメモリリークといいます。主に、このメモリリークはIEでのみ発生します。
thisオブジェクト
thisは、現在のスコープを表すオブジェクトです。通常、windowオブジェクトが設定されます。
var bar = ‘test’;
function foo() {alert(this.bar);
}foo();
関数の呼び出し時に、実行スコープを変更することができます。未指定の場合は、上記のようにwindowオブジェクトが指定されます。スコープを指定するためには、callを使います。
var bar = ‘test’;
var o = {
piyo: ‘test2’
}function foo() {
alert(this.bar);
alert(this.piyo);
}foo.call( o );
スコープは、oオブジェクトになるため、this.barはundefinedになります。
デバッグテクニック
今後、この連載ではFireBugというデバッグツールを使用します。FireFox+FireBugでの開発がExt JSでは効率的ではないかと思います。
FireBugを入れたFireFoxでは、次の命令が可能になるためデバッグメッセージや、値の確認などに最適です。
console.log(変数);
引数の値を表示します。文字列、数値だけでなくオブジェクトの参照も可能です。
console.dir(変数);
引数でされたオブジェクトをツリー形式で表示することができます。console.logでオブジェクトを表示した際、クリックすることで、さらに深い階層のオブジェクトを参照できますが、console.dirを使うことで、一度にツリー表示で確認することができるため、多階層のオブジェクトを参照する場合には、console.dirを使用しましょう。
次回予告
さて、ざーっとJavaScriptの言語仕様について確認してきました。ブログということもありページに限りがあるというか、長さの制限もあるため・・・この程度にしておきます。一つずつ確認していくとJavaScriptも結構深い言語です。
次回は、「CSSの基本とCSSセレクター」で説明したセレクタを使いながら、DOMエレメントをExt JSを使って参照していきます。ちなみに、ここまでの解説は、Ext Coreでも同じことができます。
なんか、Ext JSっぽくないぞ!?華麗なUIはいつから使えるんだ?!という方は、しばらくおまちを。
Ext JSは、結構大規模なRIAフレームワークです。それ故、いきなり突っ込んでいくと死んじゃいます。というかすぐ手詰まりになるはずです。基本をしっかり押さえてから立ち向かうと、必ずすばらしい成果をあなたに与えてくれるはずです。
では、次回「Ext JS 実践開発ガイド Vol.4:Ext JSによるCSSセレクタの利用
」をお楽しみに!