■JavaScript | Top |
1.文字列
2.数値型
3.let
4.定数
5.配列
6.連想配列
7.for
8.関数
9.日付
10.eval()
11.正規表現
12.strict mode
13.HtmlからJavaScriptとStyleSheetを読み込む
14.JSON
16.location
17.history
18.screen
19.DOM操作関連
20.イベント
21.AJAX
22.JavaScriptでDOM変更後のHTML文書の内容を確認する
文字列型の宣言
JavaScriptには明確な型指定はなく var 型のみとなる。 また文字列の指定は ' でも " でもどちらでも可能。この辺はコーディングルールに従うことになると思うが、 HTMLタグの属性値は " で書くことが一般的なので属性値は " 、文字列は ' と使い分けたほうがいいかも。 例えば次のような感じで
<input type="button" value="Button" onclick="alert('test')" />
var str1 = 'abc'; var str2 = "def";
文字列長
現在の文字列内の文字数を取得する
console.log('abc'.length); // 3 console.log('あいう'.length); // 3
リファレンス:MDN
文字コードを指定してバイト単位で桁数を取得する。
文字列の連結
+ で連結する
console.log('abc' + 'def'); // 'abcdef'
文字列の分割
文字列を複数の部分文字列に区切り、文字列の配列に分割する。
区切り文字が見つからない場合は元の文字列を返す。
var str = 'abc.def.ghi'; var arr = str.split('.'); for( var i=0; i<arr.length; i++ ) { console.log(arr[i]); } // 'abc' // 'def' // 'ghi' var arr = str.split('def'); for( var i=0; i<arr.length; i++ ) { console.log(arr[i]); } // 'abc.' // '.ghi' var arr = str.split('/'); for( var i=0; i<arr.length; i++ ) { console.log(arr[i]); } // 'abc.def.ghi'
リファレンス:MDN
文字列の置換
pattern にマッチした部分文字列の一部または全てを replacement で置き換えた新しい文字列を返す。
var str = 'abc/def/abc/def/ABC'; // 先頭の一か所のみ置換 console.log( str.replace('abc', 'XYZ') ); // 'XYZ/def/abc/def/ABC' // RegExpクラスの第2引数にgを指定すると検索した文字列をすべて置換する console.log( str.replace( new RegExp('abc','g'), 'XYZ') ); // 'XYZ/def/XYZ/def/ABC' // 文字列が見つからない場合 console.log( str.replace('DEF', 'xyz') ); // 'abc/def/abc/def/ABC' // RegExpクラスの第2引数にiを指定すると大文字小文字区別しないで置換する console.log( str.replace( new RegExp('abc','gi'), 'XYZ') ); // 'XYZ/def/XYZ/def/XYZ'
リファレンス:MDN
文字列の挿入
文字列の削除
部分文字列の取得
文字列から指定位置の文字を返す。
var str = 'abc/def/abc/def'; console.log( str.charAt(5) ); // 'e' console.log( str.charAt(20) ); // 例外は発生せず空分を返す
リファレンス:MDN
この文字列の部分文字列である新しい文字列を返す。範囲指定は文字数で行う。
var str = 'abcあ/def'; // 文字列中の指定した文字の位置( 0開始 )で開始し、文字列の末尾まで続く。 console.log( str.substr( 2 ) ); // 'cあ/def' // 指定された文字の位置( 0開始 )から始まり、指定した文字数分を返す。 console.log( str.substr( 1, 3 ) ); // 'bcあ' console.log( str.substr( 10, 3 ) ); // 例外にならずに空分を返す console.log( str.substr( 1, 20 ) ); // 'bcあ/def'( 例外にはならない ) // 負の数を指定した場合は開始位置が文字列の末尾になる console.log( str.substr( -2 ) ); // ef
リファレンス:MDN
この文字列の部分文字列である新しい文字列を返す。範囲指定はインデックスで行う。
var str = 'abcあ/def'; // 文字列中の指定した文字の位置( 0開始 )で開始し、文字列の末尾まで続く。 console.log( str.substring( 2 ) ); // 'cあ/def' // 指定された文字の位置( 0開始 )から始まり、インデックス indexB - 1 にある文字までを返す。 console.log( str.substring( 1, 4 ) ); // 'bcあ' console.log( str.substring( 10, 11 ) ); // 例外にならずに空分を返す console.log( str.substring( 1, 20 ) ); // 'bcあ/def'( 例外にはならない ) console.log( str.substring( -2 ) ); // 'abcあ/def'
リファレンス:MDN
この文字列の部分文字列である新しい文字列を返す。引数に正の数を指定した場合はsubstringと同じ動作をするが、負の数を指定した場合の 動作が異なる。
var str = 'abcあ/def'; // 文字列中の指定した文字の位置( 0開始 )で開始し、文字列の末尾まで続く。 console.log( str.slice( 2 ) ); // 'cあ/def' // 指定された文字の位置( 0開始 )から始まり、インデックス indexB - 1 にある文字までを返す。 console.log( str.slice( 1, 4 ) ); // 'bcあ' console.log( str.slice( 10, 11 ) ); // 例外にならずに空分を返す console.log( str.slice( 1, 20 ) ); // 'bcあ/def'( 例外にはならない ) console.log( str.slice( -2 ) ); // 'ef'
リファレンス:MDN
文字列比較
JavaScript での等価演算子は == と === の2種類存在する。
等価演算子( == )は、変数の型を無視して内容が一致するかを比較する。
厳密等価演算子( === )は、変数の型もチェックしつつ、内容が一致するかを比較する。大文字小文字区別する。
var str = 'abcあ/def'; if( str == 'abcあ/def' ) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str == 'abcあ' ) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str == 'Abcあ/def' ) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str === 'abcあ/def' ) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str === 'abcあ' ) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str === 'Abcあ/def' ) { console.log( '一致' ); } else { console.log( '不一致' ); } // 一致 // 不一致 // 不一致 // 一致 // 不一致 // 不一致 var str = '012'; if( str == 12 ) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str === 12 ) { console.log( '一致' ); } else { console.log( '不一致' ); } // 一致 // 不一致
前方一致、または後方一致検索する。 大文字小文字区別する。
var str = 'abcあ/def'; if( str.startsWith('abc')) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str.startsWith('ABC' )) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str.endsWith('def' )) { console.log( '一致' ); } else { console.log( '不一致' ); } if( str.endsWith('DEF' )) { console.log( '一致' ); } else { console.log( '不一致' ); } // 一致 // 不一致 // 一致 // 不一致
文字列検索
文字列中で、指定された値が最初に現れたインデックスを返す。fromIndex が指定されている場合は、fromIndex 以降の範囲内で検索する。 値が見つからない場合は -1 を返す。
大文字小文字区別する。
var str = 'abcd efgh/abcd:abcd'; console.log( str.indexOf( 'cd' ) ); // 2 console.log( str.indexOf( 'CD' ) ); // -1 // 指定したインデックス以降の文字列内で検索する console.log( str.indexOf( 'cd', 12 ) ); // 12 console.log( str.indexOf( 'ab', 17 ) ); // -1 console.log( str.indexOf( 'cd', 20 ) ); // -1( 例外にならない )
リファレンス:MDN
文字列中で、指定された値が最後に現れたインデックスを返す。fromIndex が指定されている場合は、fromIndex 以前の範囲内で検索する。
なお文字列における文字は左から右にインデックス化される。一番最初の文字のインデックスは 0 で、一番最後の文字のインデックスは stringName.length - 1 となる。値が見つけられない場合、-1 を返す。
大文字小文字区別する。
var str = 'abcd efcd/abcd:abcd'; console.log( str.lastIndexOf( 'cd' ) ); // 17 console.log( str.lastIndexOf( 'CD' ) ); // -1 // 指定した インデックス 以前の文字列内で検索する console.log( str.lastIndexOf( 'cd', 12 ) ); // 12 console.log( str.lastIndexOf( 'cd', 11 ) ); // 7 console.log( str.lastIndexOf( 'cd', 1 ) ); // -1 console.log( str.lastIndexOf( 'cd', -1 ) ); // -1( 例外にならない )
リファレンス:MDN
大文字変換
任意のロケール固有のケースマッピングに従って、参照文字列の値を大文字に変換して返す。
var str = 'ABC def/あいう.'; console.log( str.toLocaleUpperCase() ); // 'ABC DEF/あいう.'
リファレンス:MDN
小文字変換
任意のロケール固有のケースマッピングに従って、参照文字列の値を小文字に変換して返す。
var str = 'ABC def/あいう.'; console.log( str.toLocaleLowerCase() ); // 'abc def/あいう.'
リファレンス:MDN
全角文字変換
半角文字変換
先頭および末尾のスペースの削除
文字列の両端の空白を削除する。
var str = ' abc def/ghe.アイウエオ '; console.log( str.trim() ); // 'abc def/ghe.アイウエオ'
リファレンス:MDN
文字列の大小判定
2 つの文字列を辞書的に比較する。
var str1 = 'abc'; var str2 = 'def'; var str3 = 'ABC'; if( str1 > str2 ) { console.log( 'str1 > str2' ); } else if( str1 < str2 ) { console.log( 'str1 < str2' ); } else { console.log( 'str1 = str2' ); } if( str1 > str3 ) { console.log( 'str1 > str3' ); } else if( str1 < str3 ) { console.log( 'str1 < str3' ); } else { console.log( 'str1 = str3' ); } // 'str1 < str2' // 'str1 > str3'
パディング
文字列型へ変換
指定された Number オブジェクトを表す 文字列を返す。 引数の radix は基数を指定する。
var m1 = 123; console.log( m1.toString(10) ); // '123' console.log( m1.toString(16) ); // '7b' // 数値型の頭に0をつけると8進数表記となる。 var m2 = 0456; console.log( m2.toString(10) ); // '302' console.log( m2.toString(16) ); // '12e'
リファレンス:MDN
+'' を使用して文字列にキャストする。 サーバーとのトラフィックを軽減するためにJavaScriptのコードをできるだけ短くすることが推奨されるが、 JavaScriptに精通していないと何をしたいのかがわかりにくいという欠点がある。
var m1 = 123 + ''; var m2 = m1 + 5; console.log( m2 ); // 1235 m1 = 123; m2 = m1 + 5; console.log( m2 ); // 128
書式変換
文字コード取得
与えられたインデックスに位置する文字の Unicode コードポイントを10進数値で返す。
var str = 'あいう'; console.log( str.charCodeAt(0) ); // 12354
リファレンス:MDN
文字列を逆順に変換
+
+オペランドのいずれかが文字列の場合、文字列連結として扱う
var m1 = 1; var m2 = '2'; console.log( m1 + m2 ); // 12 m1 = '1'; m2 = 2; console.log( m1 + m2 ); // 12
文字列を数値変換
pauseIntを使用して文字列を数値変換する。第2引数は進数を指定する。
var m1 = 1; var m2 = '2'; console.log( m1 + parseInt( m2, 10 ) ); // 12
数字の頭に+をつけると数値型にキャストされる。 サーバーとのトラフィックを軽減するためにJavaScriptのコードをできるだけ短くすることが推奨されるが、 JavaScriptに精通していないと何をしたいのかがわかりにくいという欠点がある。
// 数字の頭に + をつけると数値型にキャストされる var m1 = +'1' var m2 = m1 + 2; console.log( m2 ); // 3 m1 = '1' // +演算子の左右いずれかのオペランドが文字列の場合文字列連結となる m2 = m1 + 2; console.log( m2 ); // 12
浮動小数点数を固定小数点数に変換
浮動小数点数を固定小数点表記を用いて表現する。 引数の digits は小数点の後に現れる桁の数を指定する。
var m1 = 456.789; console.log( m1.toFixed() ); // '457' console.log( m1.toFixed(2) ); // '456.79' console.log( m1.toFixed(10) ); // '456.7890000000'
リファレンス:MDN
浮動小数点数を切り捨て
Math.floor() を使用する
var m1 = 456.789; console.log( Math.floor(m1) ); // 456 // 小数点第2位で切り捨て m1 = 456.789; m1 = m1 * 10; console.log( Math.floor(m1) / 10 ); // 456.7
~~ を使用する。~はビット反転を意味するが、ビット反転すると32bitのInt型となり小数点以下が切り捨てられるため、~を二回使用すると結果的に小数点以下が切り捨てられる。 サーバーとのトラフィックを軽減するためにJavaScriptのコードをできるだけ短くすることが推奨されるが、 JavaScriptに精通していないと何をしたいのかがわかりにくいという欠点がある。
var m1 = 456.789; console.log( ~~m1 ); // 456
浮動小数点数を切り上げ
Math.ceil() を使用する
var m1 = 456.123; console.log( Math.ceil(m1) ); // 457 // 小数点第2位で切り上げ m1 = 456.123; m1 = m1 * 10; console.log( Math.ceil(m1) / 10 ); // 456.2
四捨五入
Math.round() を使用する。 JavaScriptのround関数はいわゆる銀行丸めではなく四捨五入となる。
var m1 = 456.456; console.log( Math.round(m1) ); // 456 m1 = 456.567; console.log( Math.round(m1) ); // 457 m1 = 457.456; console.log( Math.round(m1) ); // 457 m1 = 457.567; console.log( Math.round(m1) ); // 458
let
letはブロックスコープとなる
function foo1(){ var i1 = 1; let i2 = 2; } // 関数内で宣言した変数はvar、letともにアクセス不可 console.log(i1); console.log(i2); var arr = [1, 2, 3]; for (var i=0; i<arr.length; i++) { } for (let j=0; j<arr.length; j++) { } // ブロック内で宣言した変数はvarのみアクセス可 console.log(i); console.log(j);
const
定数
const a = 'a'; console.log(a); a = 'b'; // エラーになる
配列
[]を使用する
// 空の配列を作成 var array = []; console.log(array); // [] // 配列に初期値を代入 array = [0, 1, 2, 3]; console.log(array); // [0, 1, 2, 3] // 配列に要素を追加 array[4] = 4; console.log(array); // [0, 1, 2, 3, 4] // 要素を削除 // deleteを使用しても削除はできるが、lengthプロパティ値が元の配列の要素数のままとなるなど問題が生じる array = array.slice(2, 3); console.log(array); // [2] // 値の更新 array[0] = 3; console.log(array); // [3] // 配列のコピー var array1 = [].concat(array); console.log(array1); // [3]
配列の要素数
lengthを使用する
// 配列に初期値を代入 array = [0, 1, 2, 3]; console.log(array.length); // 4 // 配列に要素を追加 array[5] = 5; // lengthはインデックス値(キー値)の最大値 + 1となる // もっとも配列で虫食い状態のデータを作成することなど普通しないが console.log(array.length); // 6
配列の要素の検索
indexOfを使用する
var str = ['aaa', 'bbb', 'ccc']; console.log(str.indexOf('bbb')); // 1 console.log(str.indexOf('ddd')); // -1
連想配列
{}を使用する
// 空の連想配列を作成 var dic = {}; console.log(dic); // {} // 連想配列に初期値を代入 dic = {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'ddd':'DDD'}; console.log(dic); // {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'ddd':'DDD'} // 連想配列に要素を追加 dic.eee = 'EEE'; console.log(dic); // {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'ddd':'DDD', 'eee':'EEE'} // 要素を削除 delete( dic.ddd ); console.log(dic); // {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'eee':'EEE'} // 値の更新 dic['bbb'] = 'FFF'; console.log(dic); // {'aaa':'AAA', 'bbb':'FFF', 'ccc':'CCC', 'eee':'EEE'} // 値の更新 dic.bbb = 'BBB'; console.log(dic); // {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'eee':'EEE'} // 連想配列のコピー var dic1 = function(){ var ret = {}; for( var key in dic ){ ret[key] = dic[key]; } return ret; }(); console.log(dic1); // {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'eee':'EEE'} // キーの列挙 console.log(Object.keys(dic)); // ["aaa", "bbb", "ccc", "eee"] // 値の列挙 console.log(Object.values(dic)); // ["AAA", "BBB", "CCC", "EEE"]
for
forを使用する
// 配列に初期値を代入 var array = ['a', 'b', 'c', 'd']; for( var key=0; key<array.length; key++ ){ console.log(array[key]); } // a // b // c // d // 配列を for in で取り出す場合、順番が保障されない for( var key in array ){ console.log(array[key]); } // a // b // c // d // 連想配列に初期値を代入 dic = {'aaa':'AAA', 'bbb':'BBB', 'ccc':'CCC', 'ddd':'DDD'}; for( var key in dic ){ console.log(dic[key]); } // AAA // BBB // CCC // DDD let iterable = [3, 5, 7]; // in は 配列のインデックスを列挙する for (let i in iterable) { console.log(i); } // 0 // 1 // 2 // of は配列の値を列挙する。連想配列に対して of は使用できない。 for (let i of iterable) { console.log(i); } // 3 // 5 // 7
二重ループから抜ける
二重ループから抜ける
var array = [['0a', '0b', '0c'] ,['1a', '1b', '1c'] ,['2a', '2b', '2c'] ,['3a', '3b', '3c']]; // 外側のループをouter_loopというラベルに指定 outer_loop: for( var i=0; i<array.length; i++ ){ for( var j=0; j<array[i].length; j++ ){ console.log( array[i][j] ); if( j == array[i].length - 1 ){ // break ラベル名を指定することで対応するラベルの式を抜ける break outer_loop; } } }
関数
functionを使用する
function foo1(){ var a = 'abc'; return a; } console.log( foo1() ); // abc function foo2(param){ var a = param; return a; } console.log( foo2('123') ); // 123 var f = function foo3(param){ var a = param; return a; } console.log( f('AAA') ); // AAA console.log( f('xyz') ); // xyz // 複数の戻り値を返す function foo4(){ return ['aaa', 'bbb', 'ccc']; } console.log( foo4() ); // ['aaa', 'bbb', 'ccc']
即時実行関数
無名関数を使用する
(function (){ console.log('aaa'); }()); // 'aaa'
クロージャ
関数の内部で関数を宣言する。クラスを持たないJavaScriptでclassっぽいことを使用する目的で使用したりする。
var c; function MyClass(name){ var Name = ''; // 入れ子の関数を宣言 function InnerMyClass(){ Name = name; console.log(Name); } // 入れ子の関数を実行 InnerMyClass(); } c = MyClass('Tanaka'); // Tanaka c = MyClass('Sato'); // Sato function MyClass2(name){ var Name = ''; // 入れ子の関数を宣言 function InnerMyClass(){ Name = name; console.log(Name); } // 入れ子の関数を返す return InnerMyClass; } c = MyClass2('Ito'); // この段階では実行されない c(); // Ito c = MyClass2('Suzuki'); // この段階では実行されない c(); // Suzuki
プロトタイプ継承
プロトタイプ継承を使用してクラスを実装する。
ただしフィールドはpublicスコープになる。
var Name = 'Sato'; var MyClass = function(){ // コンストラクタ function MyClass( name ){ // フィールド定義 // なお関数内のthis参照は関数の呼び出し方法によって変わる。 // サンプルではコンストラクタ呼び出しのため生成したオブジェクトが参照先となる this.Name = name; } // メソッド定義(プロトタイプ継承) // なおプロトタイプ継承を使用しなくてもメソッドの実装は可能である。 // しかしプロトタイプ継承は暗黙リンクのプロパティの継承であるという性質から // オブジェクトの生成時にプロパティをメモリに展開しないという利点がある(うまく説明できんが!!) MyClass.prototype.get = function(){ return 'Hallo ' + this.Name; }; return MyClass; // コンストラクタを返す }(); var cls = new MyClass('Tanaka'); console.log(cls.get()); // Hallo Tanaka // フィールドNameは public スコープ cls.Name = 'Ito'; console.log(cls.get()); // Hallo Ito // グローバル変数への影響なし console.log(cls.Name); // Ito console.log(Name); // Sato // 生成したオブジェクトは異なるフィールドの値を持つ var cls2 = new MyClass('Suzuki'); console.log(cls.get()); // Hallo Ito console.log(cls2.get()); // Hallo Suzuki // clsのプロトタイプオブジェクトを参照確認する console.log(Object.getPrototypeOf(cls));
プロトタイプ継承を使用しないクラス定義
プロトタイプ継承を使用しないでクラスを実装する。
この場合フィールドはprivateスコープになるが、メモリ使用効率はプロトタイプ継承を使用した場合に比べて悪い(はず)
var Name = 'Sato'; function MyClass(name){ var Name = name; // MyClassのメソッドを連想配列として設定する // サンプルではget()、set(name)という2つのメソッドを設定している return { get: function(){ return 'Hallo ' + Name; } ,set: function(name){ Name = name; } }; } var cls = MyClass('Tanaka'); console.log(cls.get()); // Hallo Tanaka // フィールドNameはprivate スコープ console.log(cls.Name); // undefined // グローバル変数への影響なし console.log(Name); // Sato cls.set('Sato'); console.log(cls.get()); // Hallo Sato // フィールドに直接代入した場合、連想配列にNameキー値が追加される。 cls.Name = 'Suzuki'; console.log(cls.get()); // Hallo Sato console.log(cls.Name); // Suzuki // 生成したオブジェクトは異なるフィールドの値を持つ var cls2 = MyClass('Ito'); console.log(cls.get()); // Hallo Sato console.log(cls2.get()); // Hallo Ito
アクセッサ属性
いわゆる get set
function MyClass(name){ var Name = name; // Nameフィールドのアクセッサ設定 return { get Name(){ return 'Hallo ' + Name; } ,set Name(name){ Name = name; } }; } var cls = MyClass('Tanaka'); console.log(cls.Name); // Hallo Tanaka cls.Name = 'Sato'; console.log(cls.Name); // Hallo Sato
プロパティの上書きと削除を禁止
Object.defineProperty()を使用してプロパティの上書きおよび削除を可能とするかを設定できる。
なおアクセッサとwritableは同時に設定できない模様。ここで示すコーディング規約がプロパティの設定方法として一番堅牢であると思われる。
アクセッサを使用するかについては議論の余地があるがwritableを使用するためにアクセッサは使用しないという方針でもいいと思う。
// 'use strict'についてはstrict mode参照 'use strict'; // アクセッサを使用しない場合のサンプル function MyClass(name){ var Name = name; var o = {}; Object.defineProperty(o, 'GetName', {value: function(){ return 'Hallo ' + Name; } ,enumerable : false // プロパティの列挙禁止 ,configurable : false // プロパティの削除不可 ,writable : false // プロパティの書き込み禁止 }); Object.defineProperty(o, 'SetName', {value: function(name){ Name = name; } ,enumerable : false // プロパティの列挙禁止 ,configurable : false // プロパティの削除不可 ,writable : false // プロパティの書き込み禁止 }); return o; } var cls = MyClass('Tanaka'); console.log(cls.GetName()); // Hallo Tanaka cls.SetName('Sato'); console.log(cls.GetName()); // Hallo Sato cls.SetName = function(){ console.log('aaa'); }(); // エラーになる delete cls.SetName; // エラーになる // アクセッサを使用する場合のサンプル function MyClass2(name){ var Name = name; var o = {}; Object.defineProperty(o, 'Name', {get: function(){ return 'Hallo ' + Name; } ,set: function(name){ Name = name; } ,enumerable : false // プロパティの列挙禁止 ,configurable : false // プロパティの削除不可 //,writable : false // writableは設定不可 }); return o; } var cls2 = MyClass2('Tanaka'); console.log(cls2.Name); // Hallo Tanaka cls2.Name = 'Sato'; console.log(cls2.Name); // Hallo Sato cls2.Name = function(){ console.log('aaa'); }(); // エラーにならない delete cls2.Name; // エラーになる
リファレンス:MDN
イテレータ
反復シーケンスを実装する
// フィボナッチ数列 var FactoryFibonacciNumber = {}; // [Symbol.iterator]は引数なしの関数で、イテレーターを実装する際に必要となる FactoryFibonacciNumber[Symbol.iterator] = function(){ var Max = 10; var Prev1 = Prev2 = 1; var Count = 0; // nextメソッドで反復処理を行う FactoryFibonacciNumber.next = function(){ var Result = { value: undefined, done:true }; Count++; if (Count <= Max){ switch (Count){ case 1: case 2: Result = { value: 1, done:false }; break; default: Result = { value: Prev1 + Prev2, done:false }; Prev1 = Prev2; Prev2 = Result.value; break; } } return Result; }; return FactoryFibonacciNumber; }; // フィボナッチ数列を列挙 for (var fibo of FactoryFibonacciNumber){ console.log(fibo); }
ジェネレータ
反復シーケンスを実装する。イテレータとの違いは、yieldを使用するかだけである。
// フィボナッチ数列 // yieldを使用する場合*が必要 function* FactoryFibonacciNumber(max){ var Max = max; var Prev1 = Prev2 = 1; var Count = 0; for (Count=1; Count<Max; Count++) { var Result = { value: undefined, done:true }; switch (Count){ case 1: case 2: Result = { value: 1, done:false }; break; default: Result = { value: Prev1 + Prev2, done:false }; Prev1 = Prev2; Prev2 = Result.value; break; } // yieldを呼び出して処理が終了する。次の関数呼び出しではyieldの次の行から処理がスタートする。 yield Result; } } // フィボナッチ数列を列挙 for (var fibo of FactoryFibonacciNumber(10)){ console.log(fibo.value); }
日付
日付オブジェクト。
// システム日付を取得 var d = new Date(); console.log(d); // Mon Mar 20 2017 14:07:17 GMT+0900 (東京 (標準時)) console.log(d.getFullYear()); // 年 console.log(d.getMonth() + 1); // 月 console.log(d.getDate()); // 日 console.log(d.getHours()); // 時 console.log(d.getMinutes()); // 分 console.log(d.getSeconds()); // 秒 console.log(d.getMilliseconds()); // ミリ秒 console.log(d.getDay()); // 日曜日を0として曜日を返す // 任意の日付を設定 d.setFullYear(2011, 3, 4); console.log(d.getFullYear() + '/' + ('00' + d.getMonth()).substr(-2) + '/' + ('00' + d.getDate()).substr(-2)); // 2011/03/04 // 任意の時刻を設定 d.setHours(21, 5, 2, 100); console.log(('00' + d.getHours()).substr(-2) + ':' + ('00' + d.getMinutes()).substr(-2) + ':' + ('00' + d.getSeconds()).substr(-2) + ':' + ('000' + d.getMilliseconds()).substr(-3)); // 2011/03/04
日時の加減算
日時の加減算
// 日付の加算 var d = new Date(); console.log(d); // Mon Mar 20 2017 14:07:17 GMT+0900 (東京 (標準時)) d.setFullYear(d.getFullYear(), d.getMonth(), d.getDate() + 20); console.log(d); // Sun Apr 09 2017 14:59:30 GMT+0900 (東京 (標準時)) // 時間の減算 var d = new Date(); console.log(d); // Mon Mar 20 2017 15:02:13 GMT+0900 (東京 (標準時)) d.setHours(d.getHours(), d.getMinutes() - 10, d.getSeconds()); console.log(d); // Mon Mar 20 2017 14:52:13 GMT+0900 (東京 (標準時))
eval()
eval() 関数は文字列を JavaScript コードとして実行する。
eval('function foo(){ console.log("abc"); }'); foo(); // abc
リファレンス:MDN
正規表現で指定したパターン文字が含まれるかを判定する
指定した文字が含まれるか。
RegExpオブジェクトの第2引数にiオプションを指定すると、大文字小文字を区別しない。
var reg = new RegExp('abc'); console.log(reg.test('foo')); // false console.log(reg.test('abcdef')); // true console.log(reg.test('ab1cdf')); // false console.log(reg.test('222abc')); // true console.log(reg.test('222abc333')); // true console.log(reg.test('222ABC333')); // false // 大文字、小文字を区別しない場合はiオプションを指定する var reg = new RegExp('abc', 'i'); console.log(reg.test('222ABC333')); // true
任意の文字が含まれるか
var reg = new RegExp('abc.def'); console.log(reg.test('abcdef')); // false // abc、defの間に任意の1文字 console.log(reg.test('abc1def')); // true console.log(reg.test('abc123def')); // false var reg = new RegExp('abc...def'); console.log(reg.test('abcdef')); // false console.log(reg.test('abc1def')); // false // abc、defの間に任意の3文字 console.log(reg.test('abc123def')); // true
先頭にのみ存在するか
var reg = new RegExp('^abc'); console.log(reg.test('foo')); // false console.log(reg.test('abcdef')); // true console.log(reg.test('ab1cdf')); // false console.log(reg.test('222abc')); // false console.log(reg.test('222abc333')); // false console.log(reg.test('ABC333')); // false
末尾にのみ存在するか
var reg = new RegExp('abc$'); console.log(reg.test('foo')); // false console.log(reg.test('abcdef')); // false console.log(reg.test('ab1cdf')); // false console.log(reg.test('222abc')); // true console.log(reg.test('222abc333')); // false console.log(reg.test('222ABC')); // false
0文字以上の繰り返し(含まれない場合も真)
var reg = new RegExp('abc*456'); console.log(reg.test('abc')); // false console.log(reg.test('456')); // false // ab、456に囲まれて、文字cが0文字以上含まれる場合真 console.log(reg.test('ab456')); // true console.log(reg.test('abc456')); // true console.log(reg.test('abccc456')); // true
1文字以上の繰り返し
var reg = new RegExp('abc+456'); console.log(reg.test('abc')); // false console.log(reg.test('456')); // false // ab、456に囲まれて、文字cが1文字以上含まれる場合真 console.log(reg.test('ab456')); // false console.log(reg.test('abc456')); // true console.log(reg.test('abccc456')); // true
0文字または1文字のみの場合真
var reg = new RegExp('abc?456'); console.log(reg.test('abc')); // false console.log(reg.test('456')); // false console.log(reg.test('ab456')); // true console.log(reg.test('abc456')); // true // ab、456に囲まれて、文字cが1文字のみの場合真 console.log(reg.test('abccc456')); // false
|を区切り文字としてその両端のいずれか一方の文字が含まれるか
var reg = new RegExp('abc|123'); console.log(reg.test('abc456')); // true console.log(reg.test('def123')); // true console.log(reg.test('abc')); // true console.log(reg.test('123')); // true console.log(reg.test('def')); // false
[]内のいずれかの文字が含まれるか
var reg = new RegExp('[123]'); console.log(reg.test('abc')); // false console.log(reg.test('456')); // false console.log(reg.test('1')); // true console.log(reg.test('333')); // true
文字の範囲指定
var reg = new RegExp('[a-z]'); console.log(reg.test('abc')); // true console.log(reg.test('ABC')); // false console.log(reg.test('1')); // false var reg = new RegExp('[0-9]'); console.log(reg.test('abc')); // false console.log(reg.test('ABC')); // false console.log(reg.test('1')); // true
範囲内のいずれの文字も含まない
var reg = new RegExp('[^a-z]'); console.log(reg.test('abc')); // false console.log(reg.test('ABC')); // true console.log(reg.test('1')); // true var reg = new RegExp('[^0-9]'); console.log(reg.test('abc')); // true console.log(reg.test('ABC')); // true console.log(reg.test('1')); // false
特殊文字は\を使用してエスケープする
// .が含まれる場合真 var reg = new RegExp('[\.]'); console.log(reg.test('abc')); // false console.log(reg.test('.')); // true console.log(reg.test('abc.123')); // true // ^が含まれる場合真(^の場合\が2つ必要) var reg = new RegExp('[\\^]'); console.log(reg.test('abc')); // false console.log(reg.test('^')); // true console.log(reg.test('abc^123')); // true // $が含まれる場合真 var reg = new RegExp('[\$]'); console.log(reg.test('abc')); // false console.log(reg.test('$')); // true console.log(reg.test('abc$123')); // true // \が含まれる場合真 var reg = new RegExp('[\\\\]'); console.log(reg.test('abc')); // false console.log(reg.test('\\')); // true console.log(reg.test('abc\\123')); // true
グループ化
// 123と456の間にabcが1つのみの場合真 var reg = new RegExp('123(abc)?456'); console.log(reg.test('abc')); // false console.log(reg.test('456')); // false console.log(reg.test('123a456')); // false console.log(reg.test('123abc456')); // true console.log(reg.test('123abcabc456')); // false // 123と456の間にabcまたはdefのいずれかが1つのみの場合真 var reg = new RegExp('123(abc|def)?456'); console.log(reg.test('abc')); // false console.log(reg.test('456')); // false console.log(reg.test('123a456')); // false console.log(reg.test('123abc456')); // true console.log(reg.test('123abcabc456')); // false console.log(reg.test('123def456')); // true console.log(reg.test('123abcdef456')); // false
正規表現で指定したパターンにマッチした文字列を返す
正規表現で指定したパターンにマッチした文字列を返す。
RegExpオブジェクトの第2引数にgオプションを指定すると、マッチしたすべての文字列を返す。
var reg = new RegExp('abc+456'); console.log(reg.exec('abc')); // null console.log(reg.exec('456')); // null console.log(reg.exec('ab456')); // null console.log(reg.exec('abc456')); // abc456 // 最初に見つかった文字列のみ console.log(reg.exec('abccc456ZZZabcccccc456')); // abccc456 // execメソッドを複数回実行する場合gオプションを指定する var reg = new RegExp('abc+456', 'g'); var arr = []; while((arr = reg.exec('abccc456ZZZabcccccc456')) !== null){ console.log(arr); // abccc456, abcccccc456 }
正規表現で指定したパターンにマッチした文字列を置換
正規表現で指定したパターンにマッチした文字列を置換する
var reg = new RegExp('abc+456'); console.log('abc'.replace(reg, '000')); // abc console.log('456'.replace(reg, '000')); // 456 console.log('ab456'.replace(reg, '000')); // ab456 console.log('AAabc456CC'.replace(reg, '000')); // AA000CC console.log('abccc456ZZZabcccccc456'.replace(reg, '000')); // 000ZZZabcccccc456 // マッチしたすべての文字列を置換 var reg = new RegExp('abc+456', 'g'); console.log('abccc456ZZZabcccccc456'.replace(reg, '000')); // 000ZZZ000
strict mode
"use strict";を宣言することでstrict modeで実行される。
これにより暗黙のグローバル変数の使用といったコーディングを行った場合エラーとして処理されるようになる。
strict modeに未対応のブラウザで実行した場合は"use strict";が無意味な文字列として判断されるため何も行わない。
先頭行に"use strict";を宣言するとその後に連結されたすべてのJavaScriptがすべてstrict modeで実行されるようになる。
これは外部ライブラリも例外ではないため、strict modeに対応していない外部ライブラリを使用した場合エラーになる可能性がある。
したがってstrict modeはJavaScript全体に適用するのではなく関数単位で適用するようにしたほうが望ましい。
なお、以下に示す例はエラーチェックをすべて網羅していないことに注意すること。
※evalとかargumentsとか使うか?
スクリプト全体に適用
スクリプト全体を strict mode にする
// 先頭行に記述するとスクリプト全体が strict mode になる。 // この場合、以降に呼び出された他のスクリプトも strict mode になる。 "use strict"; a = 2; // エラーになる
リファレンス:MDN
関数単位で適用
関数内に限定して strict mode にする
function foo(){ // 関数単位でのstrict mode適用 "use strict"; // エラーになる b = 3; } foo();
リファレンス:MDN
暗黙のグローバル変数の使用の禁止
var または let で宣言していない変数を使用した場合エラーになる
function foo1(){ "use strict"; var a = 3; } function foo2(){ "use strict"; let b = 3; } function foo3(){ "use strict"; // エラーになる c = 3; } foo1(); foo2(); foo3();
リファレンス:MDN
関数内でthis参照がグローバルオブジェクトを参照しない
関数内でthis参照がグローバルオブジェクトを参照している場合エラーになる
var a = 0; function foo1(){ "use strict"; var b = 0; a = 1; } function foo2(){ "use strict"; var b = 0; // エラーになる this.a = 1; } foo1(); foo2();
リファレンス:MDN
NaN, Infinity, undefinedは読み込み専用
NaN, Infinity, undefinedのグローバル変数の値を変更しようとするとエラーになる
function foo1(){ "use strict"; NaN = 'a'; // エラーになる Infinity = 'a'; // エラーになる undefined = 'a'; // エラーになる } foo1();
リファレンス:MDN
書き込みできないプロパティへの書き込み禁止
書き込みできないプロパティへ書き込みするとエラーになる。
function foo1(){ "use strict"; var obj1 = {}; Object.defineProperty(obj1, "x", { value: 42, writable: false }); obj1.x = 9; // エラーになる } foo1();
リファレンス:MDN
削除できないプロパティは削除禁止
削除できないプロパティは削除しようとするとエラー
function foo1(){ "use strict"; delete Object.prototype; // エラーになる } foo1();
リファレンス:MDN
同名のプロパティ名の禁止
同名のプロパティを設定しようとするとエラーになる
function foo1(){ "use strict"; var o = { p: 1, p: 2 }; // エラーになるはずだがChromeでエラーにならなかった(2017/3/26現在) } foo1();
リファレンス:MDN
同名の仮引数の禁止
同名の仮引数を使用するとエラーなる
function foo1(a, a, b){ // エラーになる "use strict"; } foo1(1, 2, 3);
リファレンス:MDN
8進数表記の禁止
先頭に0を付加すると8進数表記となるが、strict mode では8進数を使用するとエラーになる。
function foo1(){ "use strict"; var sum = 011 + 12; // エラーになる } foo1();
リファレンス:MDN
withの禁止
withを使用することでオブジェクトのプロパティにアクセスする際、オブジェクト名を省略することができる。
しかしwithを使用することで意図しないオブジェクトに関連する可能性があるためバグになる可能性がある。
そのためstrict modeではwithを禁止している。
var o = { p1: 1, p2: 2 }; with(o){ console.log(p1); console.log(p2); } function foo1(){ "use strict"; var o1 = { p1: 1, p2: 2 }; with(o1){ // エラーになる console.log(p1); console.log(p2); } } foo1();
リファレンス:MDN
HtmlからJavaScriptとStyleSheetを読み込む
HtmlからJavaScriptとStyleSheetを読み込む。
<!DOCTYPE HTML> <!-- HTML5で作成された文書であることを宣言 --> <html lang="ja"> <!-- 言語を日本語として指定 --> <head> <meta charset="UTF-8"> <!-- 文書の文字コードをUTF-8とする。ファイルの保存時の文字コードを合わせること --> <meta http-equiv="Pragma" content="no-cache"> <!-- キャッシュ無効 --> <meta http-equiv="Cache-Control" content="no-cache"> <!-- キャッシュ無効 --> <title>サンプル</title> <!-- スタイルシートの読み込み --> <link rel="stylesheet" type="text/css" href="css/sample.css" charset="UTF-8"> <!-- JavaScriptの読み込み --> <!-- async:非同期でJavaScriptを読み込む --> <!-- defer:該当のScriptの実行を他のScriptの実行後に遅延する --> <script src="js/sample.js" charset="UTF-8" async defer></script> </head> <body> aaa </body> </html>
json形式の文字列をjsonオブジェクトにパースする
json形式の文字列をjsonオブジェクトにパースする。サンプルはChrome デベロッパーツールのSnippetsを使用して確認する。
var json = '{"key1":"data1", "key2":"data2"}'; console.log(JSON.parse(json));
jsonオブジェクトを文字列に変換する
jsonオブジェクトを文字列に変換する。サンプルはChrome デベロッパーツールのSnippetsを使用して確認する。
var json = {"key1":"data1", "key2":"data2"}; console.log(JSON.stringify(json));
Closure Compiler
Googleが提供しているコード圧縮・最適化・コードチェックツール。 Web版はこちら
Optimization:圧縮方式
Whitespace only :コメントとホワイトスペースの除去のみ。
Simple:Whitespace only に加えて、変数名の短縮化、改行の除去、到達不能コードの除去など
Advanced:クラス属性名の短縮化など
Formatting:出力フォーマット
Pretty print:いい感じに改行とインデントを付与する。
Print input delimiter:複数のファイルを同時にコンパイルした場合に、区別できるように // Index X を追加する。
リファレンス:Closure Compiler 公式サイト
location
location.hrefにurlを入力するとページ遷移する。
// InputタグのIdを取得 var obj = document.getElementById("aaa"); // Inputタグにclickイベントを追加 obj.addEventListener('click', function(){ // 履歴を残してページ遷移 location.href="default2.html"; // 履歴を残さないでページ遷移 location.replace("default2.html"); // ブラウザキャッシュを無視して再読み込み location.reload(true); // ブラウザキャッシュを使用して再読み込み location.reload(false); });
history
履歴を戻ったり、進めたりする
history.back(); // 履歴を戻る history.forward(); // 履歴を進める history.go(1); // 履歴を1つ進める history.go(-1); // 履歴を1つ戻る
screen
デスクトップ領域の大きさや色、向き
// InputタグのIdを取得 var obj = document.getElementById("aaa"); // Inputタグにclickイベントを追加 obj.addEventListener('click', function(){ // ウィンドウで利用可能である水平空間の大きさ (ピクセル単位) var screenWidth = screen.availWidth; // Windows でのタスクバーのような、オペレーティングシステムによって表示されている、 // 固定あるいは半固定されているユーザインタフェース部分を引いた画面の高さ (ピクセル単位) // とのことだが実際にはタスクバーも含めたサイズが取得される。 var screenHeight = screen.availHeight; var width = 640; var height = 480; var left = ( screenWidth - width ) * 0.5; var top = ( screenHeight - height ) * 0.5; // 子画面をデスクトップの中心に表示 window.open("default2.html", "テスト", "left=" + left + ",top=" + top + ",width=" + width + ",height=" + height); });
DOM操作関連
HTMLやXMLを操作するためのAPI
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="foo1">aaa</div> <div class="foo2">bbb</div> <div class="foo2">ccc</div> </body> </html>
window.addEventListener('load', function(){ // HTML内で一意になるid属性で検索 console.log( document.getElementById("foo1").textContent ); // aaa // HTML内のclass属性で検索。複数の要素を取得できる var arr = document.getElementsByClassName("foo2"); for( let obj of arr ){ console.log(obj.textContent); } // bbb // ccc // タグ名で検索。*を指定するとすべてのタグを取得する var arr = document.getElementsByTagName("div"); for( let obj of arr ){ console.log(obj.textContent); } // aaa // bbb // ccc }, false);
ノードの作成・追加・削除
ノードの作成と追加と削除
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="foo1">aaa</div> <div id="foo2">bbb</div> <div class="foo3">ccc</div> </body> </html>
window.addEventListener('load', function(){ // div要素作成 var newDiv = document.createElement('div'); // テキスト要素を作成してdiv要素に追加 newDiv.appendChild(document.createTextNode('ddd')); // class属性設定 newDiv.class = "foo4"; // 属性要素作成 var att = document.createAttribute('attr'); // 属性値を設定 att.value="foo5"; // 属性要素をnewDivに追加 newDiv.setAttributeNode(att); // body要素に追加 document.body.appendChild(newDiv); // a要素作成 var newNode = document.createElement('a'); // id属性設定 newNode.id = "foo6"; // テキスト要素を作成してa要素に追加 newNode.appendChild(document.createTextNode('eee')); // foo1取得 var oldNode = document.getElementById('foo1'); // foo1の親ノードを取得 var parentNode = oldNode.parentNode; // oldNodeをnewNodeで置き換える parentNode.replaceChild(newNode, oldNode); // foo2取得 var elm = document.getElementById("foo2"); // foo2削除 elm.parentNode.removeChild(elm); console.log(document.body); }, false);
ライブオブジェクト
getElementsByClassName()メソッドやgetElementsByTagName()メソッドで取得できるオブジェクトは配列ではなくHTMLCollectionオブジェクトである。
このオブジェクトはライブオブジェクトといい、ライブオブジェクトを取得した後に要素を追加および削除した後の状態も知っているという特徴がある。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="foo1">aaa</div> <div class="foo2">bbb</div> <div class="foo2">ccc</div> </body> </html>
window.addEventListener('load', function(){ var arr = document.getElementsByTagName("div"); for( let obj of arr ){ console.log(obj.textContent); } // aaa // bbb // ccc var newDiv = document.createElement('div'); newDiv.appendChild(document.createTextNode('ddd')); var att = document.createAttribute('class'); att.value="foo2"; newDiv.setAttributeNode(att); document.body.appendChild(newDiv); // 取得済のarrの値も変更されている for( let obj of arr ){ console.log(obj.textContent); } // aaa // bbb // ccc // ddd }, false);
ライブオブジェクトのパフォーマンス
ライブオブジェクトをそのままループで使用するとパフォーマンスが遅くなるのでArrayに変換してから使用すること
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="foo1">aaa</div> <div class="foo2">bbb</div> <div class="foo2">ccc</div> </body> </html>
window.addEventListener('load', function(){ var arr = document.getElementsByTagName("div"); console.time("計測1"); for( let obj of arr ){ console.log(obj.textContent); } console.timeEnd("計測1"); // 計測1: 5.97ms // タグ名で要素を取得し、Arrayに変換する var arr2 = Array.prototype.slice.call(document.getElementsByTagName("div")); console.time("計測2"); for( let obj of arr2 ){ console.log(obj.textContent); } console.timeEnd("計測2"); // 計測2: 0.702ms }, false);
innerHTML
直接タグをぶっこむ。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="my1-id"> <div class="my2-cls">aaa</div> </div> <div id="my2-id"> <div class="my2-cls">bbb</div> <div class="my4-cls">ddd</div> </div> <div class="my3-cls">bbb</div> <div class="my3-cls">ccc</div> </body> </html>
window.addEventListener('load', function(){ var elm = document.getElementById("my1-id"); // my1-idの子要素を置き換える elm.innerHTML = "<div id='my3-id'><div class='my5-cls'>eee</div></div>"; console.log(document.body); }, false);
DOM操作のパフォーマンス
タグ追加時のパフォーマンスの向上
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="my1-id"> </div> </body> </html>
window.addEventListener('load', function(){ var elm = document.getElementById("my1-id"); console.time("計測1"); for(let i=0; i<10; i++){ var child = document.createElement('div'); child.appendChild(document.createTextNode(i)); // 追加するたびに再描画するため遅い elm.appendChild(child); } console.timeEnd("計測1"); var fragment = document.createDocumentFragment(); console.time("計測2"); for(let i=0; i<10; i++){ var child = document.createElement('div'); child.appendChild(document.createTextNode(i)); // fragmentに追加 fragment.appendChild(child); } // fragmentに追加した子要素をまとめてmy1-idに追加し再描画 elm.appendChild(fragment); console.timeEnd("計測2"); }, false);
イベントハンドラ
on...で設定する。1つの要素・イベントについて1つしか設定できない。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> </head> <body> <input type="button" value="ボタン" onclick="alert('aaa');alert('bbb');"/> </body> </html>
イベントリスナ
addEventListener()でイベントを設定する。この場合イベントハンドラと異なり1つの要素に複数のイベントを設定できる。
外部ライブラリを使用した場合などで効果的になる場合があるまた第3引数はイベントの伝播方式を示し、キャプチャリングフェーズで伝播させる場合は true にする。この場合、windowからイベント発生元の要素までたどってイベントを発生させていく。
false にした場合は、バブリングフェーズで伝播し、イベントの発生元からwindowに向かってイベントを発生させていく。
なおfocusイベントのように伝播しないイベントも存在する。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> <style> #outer { width: 150px; height: 150px; background: #00AAFF; padding-top: 50px; padding-left: 50px; } #inner { width:100px; height: 100px; background: #EEFF00 } </style> </head> <body> outer <div id="outer"> <div id="inner">inner</div> </div> <div id="text1"></div></br> <div id="text2"></div></br> </body> </html>
window.addEventListener('load', function(){ document.getElementById('outer').addEventListener('click', function(){ document.getElementById('text1').textContent = 'outer'; }, false); // 同一の要素に同一のイベントを追加してもすべてのイベントが発生する document.getElementById('outer').addEventListener('click', function(){ document.getElementById('text2').textContent = 'outer'; }, false); }, false);
window.addEventListener('load', function(){ document.getElementById('outer').addEventListener('click', function(){ alert('outer'); }, false); // innerをクリックすると inner -> outer の順番にイベントが実行される。当然だが outer をクリックしても伝播しない。 document.getElementById('inner').addEventListener('click', function(){ alert('inner'); }, false); }, false);
window.addEventListener('load', function(){ document.getElementById('outer').addEventListener('click', function(){ alert('outer'); }, true); // innerをクリックすると outer -> inner の順番にイベントが実行される。当然だが outer をクリックしても伝播しない。 document.getElementById('inner').addEventListener('click', function(){ alert('inner'); }, false); }, false);
イベントを伝播させない
stopPropagation()メソッドを使用すると次以降に伝播されるリスナーのイベントが発生しない。 同一の要素にイベントを追加している場合にstopImmediatePropagation()メソッドを使用すると、以降に発生するイベントが発生しない。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> <style> #outer { width: 150px; height: 150px; background: #00AAFF; padding-top: 50px; padding-left: 50px; } #inner { width:100px; height: 100px; background: #EEFF00 } </style> </head> <body> outer <div id="outer"> <div id="inner">inner</div> </div> <div id="text1"></div></br> <div id="text2"></div></br> </body> </html>
window.addEventListener('load', function(){ document.getElementById('outer').addEventListener('click', function(){ alert('outer'); }, false); document.getElementById('inner').addEventListener('click', function(event){ // innerのみ実行される event.stopPropagation(); alert('inner'); }, false); }, false);
window.addEventListener('load', function(){ // イベントが発生する document.getElementById('outer').addEventListener('click', function(){ alert('outer1'); }, false); // イベントが発生する document.getElementById('outer').addEventListener('click', function(){ event.stopImmediatePropagation(); alert('outer2'); }, false); // イベントが発生しない document.getElementById('outer').addEventListener('click', function(event){ alert('outer3'); }, false); }, false);
標準処理をキャンセル
Webブラウザが標準的に実装している処理をキャンセルする。
ただしblurイベントなど一部のイベントはキャンセルできない。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <a href='aaa.html' id='foo'>リンク</a> </body> </html>
window.addEventListener('load', function(){ document.getElementById('foo').addEventListener('click', function(event){ // ページ遷移させない event.preventDefault(); }, false); }, false);
タイマーイベント
連続で実行するタイマーイベントを設定する
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> </body> </html>
window.addEventListener('load', function(){ var counter = 0; var countup = function(){ console.log(new Date()); counter++; if( counter < 10 ){ setTimeout(countup, 1000); } } countup(); }, false);
以下にイベントの一覧を示す。ただしChromeでのみ動作確認を行っており、他のブラウザでは挙動が変わる場合があるので実装の際には注意すること。
またすべてのイベントを網羅していないことにも注意すること。■UIEvent一覧
load 文書のロードが完了した段階で発生。ページが完全に読み込まれたことを検出する必要がある場合を除き、DOMContentLoadedイベントを使用すべき。 unload ページ遷移が発生した場合など文書のアンロードされた beforeunload 文書がアンロードされる直前に発生する。
ページ遷移の確認メッセージ表示で使用する。
window.addEventListener('beforeunload', function(event){ // 文字列が returnValue イベントプロパティに割り当てられている場合、ダイアログボックスが表示される。 event.returnValue='確認'; }, false);select input要素やtextarea要素でテキストが選択された resize ウィンドウサイズが変更された scroll 要素がスクロールした ■FocusEvent一覧
focus 要素がフォーカスを得た blur 要素がフォーカスを失った ■MouseEvent一覧
click 要素がクリックされた場合に発生する。左クリックでのみ発生する。 dblclick 要素がダブルクリックされた場合に発生する。左ダブルクリックでのみ発生する。 mousedown マウスボタンが要素上で押下された場合に発生する。マウスのすべてのボタンに対してイベントが発生する。 mouseup 押下されたマウスボタンが要素上で放された場合に発生する。マウスのすべてのボタンに対してイベントが発生する。 mouseenter マウスポインタが要素の上にのった mouseleave マウスポインタが要素の上から離れた mousemove マウスポインタが要素の上を移動した
window.addEventListener('load', function(event){ var obj = document.getElementById('foo'); obj.addEventListener('mousemove', function(event){ // イベントを割り当てたタグ上でマウスカーソルが移動した場合、ページの左上を原点とするマウスカーソルの座標を取得 console.log(event.pageX + ':' + event.pageY); }, false); }, false);■WheelEvent一覧
wheel マウスホイールが回された場合に発生する。移動量はxyz方向それぞれに対し、deltaX、deltaY、deltaZプロパティで取得できる。
window.addEventListener('load', function(event){ var obj = document.getElementById('foo'); obj.addEventListener('wheel', function(event){ // マウスホイールの移動量を取得 console.log(event.deltaY); }, false); }, false);
keydown キーが押下された
window.addEventListener('load', function(event){ var obj = document.getElementById('foo'); obj.addEventListener('keydown', function(event){ // 入力されたキーコードを取得 console.log(event.code); }, false); }, false);keypress Ctrlなどの制御キーを除くキーが入力された場合に発生する。
window.addEventListener('load', function(event){ var obj = document.getElementById('foo'); obj.addEventListener('keypress', function(event){ // 入力されたキー値を取得 console.log(event.key); }, false); }, false);keyup 押下されていたキーが離された
compositionstart IMEで全角文字入力モードで初めて入力された compositionupdate IMEで全角文字入力モードで入力すると発生する。変換した場合も発生する。
window.addEventListener('load', function(event){ var obj = document.getElementById('foo'); obj.addEventListener('compositionupdate', function(event){ // 入力された全角文字 console.log(event.data); }, false); }, false);compositionend IMEで全角文字入力モードで入力して確定した
AJAX
クライアントとサーバー間で非同期通信を行う。
<!-- HTML --> <!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>サンプル</title> <script src="js/sample.js" charset="UTF-8"></script> </head> <body> <div id="div_id"></div> <input type="button" value="ボタン" id="input_id" /> </body> </html>
// JavaScript var isProcessing = false; window.addEventListener('load', function(){ var obj = document.getElementById('input_id'); obj.addEventListener('click', function(){ if (isProcessing){ return; } isProcessing = true; var xhr = new XMLHttpRequest(); // ステータスが変更された際に発生するイベントの設定 xhr.onreadystatechange = function(){ // 受信終了 if (xhr.readyState == 4){ // 200:成功 // 304:前回の送信内容と同じ if (xhr.status == 200 || xhr.status == 304){ // 文字列をJSON形式にパース。 var data = JSON.parse(xhr.responseText); console.log(data); var obj2 = document.getElementById('div_id'); var s = ''; for( var d of data ){ s += d + ', '; } obj2.textContent = s; isProcessing = false; } // ステータスが0になるときがあるのでそれは除外しておく else if(xhr.status > 0){ console.log(xhr.status + ':' + 'error!!'); isProcessing = false; } } }; // リクエストを初期化する // 第3引数がtrueの場合は非同期通信となる xhr.open('GET', 'http://localhost/WebAPI/api/values/', true); // HTTPリクエストヘッダの値を設定 // If-Modified-Sinceは条件付きリクエストで、サーバーから304が返信された場合ブラウザはキャッシュを使用する xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT'); // リクエストを送信する。非同期通信の場合ここで待ちが発生しない。 xhr.send(null); }, false); }, false);
// ASP.NET WebAPI // ValuesController.cs using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace WebApplication2.Controllers { public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", DateTime.Now.ToString() }; } } }
JavaScriptでDOM変更後のHTML文書の内容を確認する
Chromeの場合にJavaScriptでDOM変更後のHTML文書の内容を確認する方法を示す。
F12押下でChromeデベロッパー・ツールを表示し、Consoleタブを選択後以下を入力する。document.getElementsByTagName('HTML')[0].innerHTML
なおFirefoxでF12押下で表示される開発ツールの場合は、HTMLタブを選択するとそのままで表示できる。このあたりはFirefoxを使用したほうが便利。