新規記事の投稿を行うことで、非表示にすることが可能です。
2012年07月24日
スクリプトタグに引数を指定する
よく、以下のような構文を見ることがあります。
<script src="example.js?arg=value"></script>
普通に実行すると「arg=value」は無視されてしまいます。
それでは、どのように引数を拾っているのでしょうか?
これは、DOM 構築中であるところがポイントで、
そこまでに構築されている DOM の末尾が、この script タグになっています。
つまり、本スクリプト内で、以下を実行すると、自分自身の要素が返ってきます。
var elms = document.getElementsByTagName('script');
var elm = elms[elms.length - 1];
自分の要素を拾えたら、src 属性を見て、引数を自前で解析します。
解析には正規表現が便利でしょう。
var reg = /\w+.js\??(.*)/;
var prms = elm.src.match(reg);
// 結果確認用
alert(prms.join('|'));
{a8.net http://books.livedoor.com/item/1903118}
<script src="example.js?arg=value"></script>
普通に実行すると「arg=value」は無視されてしまいます。
それでは、どのように引数を拾っているのでしょうか?
これは、DOM 構築中であるところがポイントで、
そこまでに構築されている DOM の末尾が、この script タグになっています。
つまり、本スクリプト内で、以下を実行すると、自分自身の要素が返ってきます。
var elms = document.getElementsByTagName('script');
var elm = elms[elms.length - 1];
自分の要素を拾えたら、src 属性を見て、引数を自前で解析します。
解析には正規表現が便利でしょう。
var reg = /\w+.js\??(.*)/;
var prms = elm.src.match(reg);
// 結果確認用
alert(prms.join('|'));
{a8.net http://books.livedoor.com/item/1903118}
【このカテゴリーの最新記事】
-
no image
-
no image
-
no image
-
no image
-
no image
posted by FJT at 05:39| javascript
2012年07月20日
画面の切替方法について
画面の切替方法について、ちょっと考えています。
A画面からB画面に遷移するときに、B画面の Frame を取得して
setCurrent をしていますが、その瞬間に
setCurrent を実行したプログラムは中断されてしまうようです。
B画面については、たとえばA画面からの子画面だとして、
そこからA画面に戻るときに、A画面に対して setCurrent する必要があります。
A画面に遷移を戻す際は、A画面の Frame が必要です。
解決策として、コンストラクタの引数に、遷移元の Frame を指定することで解決しそうです。
でも、何か使い方がしっくりきません。
CarRace では、メインとなるクラス経由で、各画面を呼出すようになっていました。
Static で呼び出しているようなのですが、この使い方も、何かしっくりきません。
今は、コンストラクタから Frame を指定して、callback という名前のメソッドを
呼出すようにしています。callback の実行時には this に
自分自身の Frame が入っているので、そのまま setCurrent(this) とすればいいわけです。
今思いつきで書いていますが、
広域変数でスタックトレースを用意するのもいい方法だと思いました。
画面呼出し時にスタックをためていき、画面を戻るときにスタックを消費していきます。
後はスタックトレース専用のクラスがあればいいことになります。
{a8.net http://books.livedoor.com/item/1062223}
A画面からB画面に遷移するときに、B画面の Frame を取得して
setCurrent をしていますが、その瞬間に
setCurrent を実行したプログラムは中断されてしまうようです。
B画面については、たとえばA画面からの子画面だとして、
そこからA画面に戻るときに、A画面に対して setCurrent する必要があります。
A画面に遷移を戻す際は、A画面の Frame が必要です。
解決策として、コンストラクタの引数に、遷移元の Frame を指定することで解決しそうです。
でも、何か使い方がしっくりきません。
CarRace では、メインとなるクラス経由で、各画面を呼出すようになっていました。
Static で呼び出しているようなのですが、この使い方も、何かしっくりきません。
今は、コンストラクタから Frame を指定して、callback という名前のメソッドを
呼出すようにしています。callback の実行時には this に
自分自身の Frame が入っているので、そのまま setCurrent(this) とすればいいわけです。
今思いつきで書いていますが、
広域変数でスタックトレースを用意するのもいい方法だと思いました。
画面呼出し時にスタックをためていき、画面を戻るときにスタックを消費していきます。
後はスタックトレース専用のクラスがあればいいことになります。
{a8.net http://books.livedoor.com/item/1062223}
2012年07月15日
正規表現について
正規表現について、特に注意することを書いておきます。
文字列を特定の文字で区切る場合として、以下の構文がよく使われます。
// 1) 縦棒で区切る
var a = "ab|cd|ef|gh".split("|");
// 2) 縦棒で区切る
var a = "ab|cd|ef|gh".split(/|/);
1) 2) 両方とも同じ結果になりますが、違いとしては、
1) が文字列、2) が正規表現で区切っています。
"/"で区切られた場合は正規表現です。
正規表現は、以下の表記でも表すことができます。
// 3) 縦棒で区切る
var a = "ab|cd|ef|gh".split(new RegExp("|"));
2) と 3) は機能的には同じですが、3) では文字列を正規表現にすることができます。
個人的には 2) のほうは構文に不自然さを覚えます。
3) の表記について注意点です。
エスケープ記号入りの表記の場合、エスケープ記号をエスケープしておく必要があります。
// 2) 1文字以上の単語で区切る
var a = "ab|cd|ef|gh".split(/\w+/);
// 3) 1文字以上の単語で区切る
var a = "ab|cd|ef|gh".split(new RegExp("\\w+"));
正規表現オプションは、2) の場合は独特な気がします。
こちらも個人的に、文法に違和感があります。
// 2) 大文字小文字を区別しないで区切る
var a = "abcdefg".split(/cd/i);
// 3) 大文字小文字を区別しないで区切る
var a = "abcdefg".split(new RegExp("cd", "i");
{a8.net http://books.livedoor.com/item/1443887}
文字列を特定の文字で区切る場合として、以下の構文がよく使われます。
// 1) 縦棒で区切る
var a = "ab|cd|ef|gh".split("|");
// 2) 縦棒で区切る
var a = "ab|cd|ef|gh".split(/|/);
1) 2) 両方とも同じ結果になりますが、違いとしては、
1) が文字列、2) が正規表現で区切っています。
"/"で区切られた場合は正規表現です。
正規表現は、以下の表記でも表すことができます。
// 3) 縦棒で区切る
var a = "ab|cd|ef|gh".split(new RegExp("|"));
2) と 3) は機能的には同じですが、3) では文字列を正規表現にすることができます。
個人的には 2) のほうは構文に不自然さを覚えます。
3) の表記について注意点です。
エスケープ記号入りの表記の場合、エスケープ記号をエスケープしておく必要があります。
// 2) 1文字以上の単語で区切る
var a = "ab|cd|ef|gh".split(/\w+/);
// 3) 1文字以上の単語で区切る
var a = "ab|cd|ef|gh".split(new RegExp("\\w+"));
正規表現オプションは、2) の場合は独特な気がします。
こちらも個人的に、文法に違和感があります。
// 2) 大文字小文字を区別しないで区切る
var a = "abcdefg".split(/cd/i);
// 3) 大文字小文字を区別しないで区切る
var a = "abcdefg".split(new RegExp("cd", "i");
{a8.net http://books.livedoor.com/item/1443887}
posted by FJT at 00:48| javascript
2012年07月12日
fireEvent 関係を使う場合の注意
イベントを起動させる処理として、fireEvent と createEvent ~ dispatchEvent があります。
ここで注意しなければらないことがあります。
イベント登録時には、以下のようなコードで行うのが一般的です。
if(window.addEventListener) {
window.addEventListener(〜);
} else if(window.attachEvent) {
window.attachEvent(〜);
}
これは、まず addEventListener がサポートされているかを判定して、あれば使います。
無ければ、attachEvent がサポートされているかを判定して、あれば使います。
ここに、イベント起動の処理を以下のように考えてみましょう。
if(window.fireEvent) {
window.fireEvent(〜);
} else if(window.createEvent) {
var evt = window.createEvent(〜);
evt.initEvent(〜);
window.dispatchEvent(evt);
}
コードをこのようにすると、IE9で不具合があります。
まず、イベント登録処理ですが、IE9は attachEvent だけではなく、
addEventListener にも対応しています。
つまり、IE9の場合は addEventListener でイベント登録されます。
次にイベント起動処理ですが、ここではIE9の場合、IE固有の fireEvent が起動します。
このとき、addEventListener で登録したイベントは fireEvent で動かない、
または不安定な動きになるようです。
正しく動かすためには、addEventListener よりも前に
attachEvent を判定すればよいことになります。
{a8.net http://books.livedoor.com/item/1752906}
ここで注意しなければらないことがあります。
イベント登録時には、以下のようなコードで行うのが一般的です。
if(window.addEventListener) {
window.addEventListener(〜);
} else if(window.attachEvent) {
window.attachEvent(〜);
}
これは、まず addEventListener がサポートされているかを判定して、あれば使います。
無ければ、attachEvent がサポートされているかを判定して、あれば使います。
ここに、イベント起動の処理を以下のように考えてみましょう。
if(window.fireEvent) {
window.fireEvent(〜);
} else if(window.createEvent) {
var evt = window.createEvent(〜);
evt.initEvent(〜);
window.dispatchEvent(evt);
}
コードをこのようにすると、IE9で不具合があります。
まず、イベント登録処理ですが、IE9は attachEvent だけではなく、
addEventListener にも対応しています。
つまり、IE9の場合は addEventListener でイベント登録されます。
次にイベント起動処理ですが、ここではIE9の場合、IE固有の fireEvent が起動します。
このとき、addEventListener で登録したイベントは fireEvent で動かない、
または不安定な動きになるようです。
正しく動かすためには、addEventListener よりも前に
attachEvent を判定すればよいことになります。
{a8.net http://books.livedoor.com/item/1752906}
posted by FJT at 22:34| javascript
2012年07月10日
宣言部について
久しぶりの DoJa ネタです。
着々と進んでいるのですが、紹介できる技術ではなかったので、特に書きませんでしたが、
今回は宣言部について、もしかして皆さん理解されているかもしれませんが、書いておきます。
変数の宣言については、以下のキーワードをよく使います。
static
final
まず static ですが、インスタンス化しなくても使える変数です。
class Test{
static int A = 0;
public int B = 0;
}
普通に宣言されている変数 B については、以下のようにインスタンス化して使います。
Test t = new Test();
// ログウィンドウに Test インスタンスの B の内容を出力
System.out.println(t.B);
static の場合、これをクラスの段階で使うことができるようになります。
// Test クラスの A プロパティを出力
System.out.println(Test.A);
インスタンス化しなくても使える、たとえばコンストラクタに引き渡す固定値などに有効でしょう。
次は、final についてです。一度設定したら変更できませんよ。という意味をもっています。
つまり、VBScript でいうところの Const のような使い方ができます。
private final String dummy = "DUMMY!!";
着々と進んでいるのですが、紹介できる技術ではなかったので、特に書きませんでしたが、
今回は宣言部について、もしかして皆さん理解されているかもしれませんが、書いておきます。
変数の宣言については、以下のキーワードをよく使います。
static
final
まず static ですが、インスタンス化しなくても使える変数です。
class Test{
static int A = 0;
public int B = 0;
}
普通に宣言されている変数 B については、以下のようにインスタンス化して使います。
Test t = new Test();
// ログウィンドウに Test インスタンスの B の内容を出力
System.out.println(t.B);
static の場合、これをクラスの段階で使うことができるようになります。
// Test クラスの A プロパティを出力
System.out.println(Test.A);
インスタンス化しなくても使える、たとえばコンストラクタに引き渡す固定値などに有効でしょう。
次は、final についてです。一度設定したら変更できませんよ。という意味をもっています。
つまり、VBScript でいうところの Const のような使い方ができます。
private final String dummy = "DUMMY!!";
2012年07月08日
クロージャーについて
今回は、クロージャーについて解説いたします。
普通に javascript を組んでいる人にとっては、縁のない世界かもしれません。
でも、こういうケースが出てきた場合に困ると思います。
自分で作成したスクリプトを、既存のページに追加するような要件です。
変数を作成したところ、初期化していない変数に何か値が入っています。
おや、初期化しないと適当な値が入るのかなと勝手に想像することもできます。
このときの原因は、既存スクリプトに書かれていた、同名の変数名でした。
このように、各スクリプトどうしで影響し合ってしまうので、
意図しない結果が出てくる可能性があります。
これを避けるために、最近作っているスクリプトについては、
クロージャーを使うようにしています。
(function(){
スクリプト本文
})();
以上のような構成にすると、匿名関数でラップすることによって、他のスクリプトからは
参照することができなくなります。
また、広域変数にしたくない変数定義を function 内に入れておくことによって、
変数のスコープをより明確に宣言できます。
function を囲む括弧ですが、これは関数を隠すためのものです。
最後の括弧 () ですが、この匿名関数を、この場で実行することをあらわします。
必要に応じて、括弧の中に引数をいれるようにしてもいいですね。
最近は jQuery が流行ってくると、こういったクロージャーの概念がなくても
スクリプトが組めるのですが、javascript は基本仕様が変わらず、
今でもバージョンアップされない言語で、すでにクロージャーの概念があることに驚きです。
普通に javascript を組んでいる人にとっては、縁のない世界かもしれません。
でも、こういうケースが出てきた場合に困ると思います。
自分で作成したスクリプトを、既存のページに追加するような要件です。
変数を作成したところ、初期化していない変数に何か値が入っています。
おや、初期化しないと適当な値が入るのかなと勝手に想像することもできます。
このときの原因は、既存スクリプトに書かれていた、同名の変数名でした。
このように、各スクリプトどうしで影響し合ってしまうので、
意図しない結果が出てくる可能性があります。
これを避けるために、最近作っているスクリプトについては、
クロージャーを使うようにしています。
(function(){
スクリプト本文
})();
以上のような構成にすると、匿名関数でラップすることによって、他のスクリプトからは
参照することができなくなります。
また、広域変数にしたくない変数定義を function 内に入れておくことによって、
変数のスコープをより明確に宣言できます。
function を囲む括弧ですが、これは関数を隠すためのものです。
最後の括弧 () ですが、この匿名関数を、この場で実行することをあらわします。
必要に応じて、括弧の中に引数をいれるようにしてもいいですね。
最近は jQuery が流行ってくると、こういったクロージャーの概念がなくても
スクリプトが組めるのですが、javascript は基本仕様が変わらず、
今でもバージョンアップされない言語で、すでにクロージャーの概念があることに驚きです。
posted by FJT at 01:32| javascript
2012年07月04日
301 転送と 302 転送
今回は転送設定についてです。
転送設定は、「301 Moved Permanently」と「302 Moved Temporary」の
2つがあります。
名前のとおりりなのですが、301 は永久的に転送、302 は一時的に転送です。
たとえば ASP だと次のように書きます。
'301 Moved Permanently
Response.Status = "301 Moved Permanently"
Response.AddHeader "Location", "URL"
'302 Moved Temporary
Response.Redirect "URL"
最近は、SEO対策で 301 転送がやたらと拝まれていますが、
302 転送を使うべきのところについても、無理やり 301 転送にしているものもあるようです。
これらは、きちんと用途に応じて設定したほうがいいのではないでしょうか?
ちなみに、301 転送は、永久的にリダイレクトを行なうので、
場合分けして転送している処理については向いていません。
永久リダイレクトされる特性から、301 転送はブラウザでキャッシュされる場合があります。
いったん永久転送が行われたページについては、
2回目以降はサーバーにアクセスせずに転送してしまうのです。
場合分けして 301 転送しているページでは、
キャッシュを使わないように設定する対策も考えられますが、
ここは 302 転送を使うべきだと思います。
転送設定は、「301 Moved Permanently」と「302 Moved Temporary」の
2つがあります。
名前のとおりりなのですが、301 は永久的に転送、302 は一時的に転送です。
たとえば ASP だと次のように書きます。
'301 Moved Permanently
Response.Status = "301 Moved Permanently"
Response.AddHeader "Location", "URL"
'302 Moved Temporary
Response.Redirect "URL"
最近は、SEO対策で 301 転送がやたらと拝まれていますが、
302 転送を使うべきのところについても、無理やり 301 転送にしているものもあるようです。
これらは、きちんと用途に応じて設定したほうがいいのではないでしょうか?
ちなみに、301 転送は、永久的にリダイレクトを行なうので、
場合分けして転送している処理については向いていません。
永久リダイレクトされる特性から、301 転送はブラウザでキャッシュされる場合があります。
いったん永久転送が行われたページについては、
2回目以降はサーバーにアクセスせずに転送してしまうのです。
場合分けして 301 転送しているページでは、
キャッシュを使わないように設定する対策も考えられますが、
ここは 302 転送を使うべきだと思います。
2012年07月01日
イベント登録順で処理されない
比較的知られている話ですが、addEventListener, attachEvent で、
イベントハンドラを複数登録できます。
複数登録されたイベントハンドラは、つい登録した順番に実行されるのかと思いましたが、
保証されているわけではありません。実際に、実行順序が登録順ではない場合もあるようです。
もし、各ライブラリが完全独立していて、
イベントハンドラを登録順に実行したい場合はどのようにすればよいかというと、
登録したいイベントハンドラを配列に格納しておき、
配列の中身を順番に実行する処理を、ひとつだけイベントハンドラとして
登録しておく手段があります。
だいたい、以下のようなコードになると思います。
var onloader = function() {
var self = arguments.callee;
var handlers = [];
self.addEvent = function(func){
handlers.push(func);
}
// onLoad 処理で、イベントハンドラが登録された順番に実行する
function onLoad(){
for(var ind = 0, max = handlers.length; ind < max; ind++) {
if(handlers[ind]) {
handlers[ind]();
}
}
}
// イベントハンドラ登録
if(window.attachEvent) {
window.attachEvent('onload', onLoad);
} else if(window.addEventListener) {
window.addEventListener('load', onLoad);
}
return self;
};
イベントハンドラを複数登録できます。
複数登録されたイベントハンドラは、つい登録した順番に実行されるのかと思いましたが、
保証されているわけではありません。実際に、実行順序が登録順ではない場合もあるようです。
もし、各ライブラリが完全独立していて、
イベントハンドラを登録順に実行したい場合はどのようにすればよいかというと、
登録したいイベントハンドラを配列に格納しておき、
配列の中身を順番に実行する処理を、ひとつだけイベントハンドラとして
登録しておく手段があります。
だいたい、以下のようなコードになると思います。
var onloader = function() {
var self = arguments.callee;
var handlers = [];
self.addEvent = function(func){
handlers.push(func);
}
// onLoad 処理で、イベントハンドラが登録された順番に実行する
function onLoad(){
for(var ind = 0, max = handlers.length; ind < max; ind++) {
if(handlers[ind]) {
handlers[ind]();
}
}
}
// イベントハンドラ登録
if(window.attachEvent) {
window.attachEvent('onload', onLoad);
} else if(window.addEventListener) {
window.addEventListener('load', onLoad);
}
return self;
};
posted by FJT at 22:32| javascript
2012年06月22日
onLoad よりも早く
今回は javascript のお話です。
要素が全部読込まれた後に実行させたいメソッドを定義するとき、
よくあるのは onLoad イベントで記述すると思います。
<body onload="javascript:initialize()">〜
または
// IE
if(document.attachEvent)
document.attachEvent('onload', initialize);
// Mozilla
if(document.addEventListener)
document.addEventListener('load', initialize, false);
onLoad イベントは、画像などのファイルが全部読込まれてから起動しますので、
イベント内で初期値を設定している場合、画面が表示されてから
勝手に入力項目に値が入ったような印象を受けます。
見た目も、ううむ、と考えさせられてしまいます。
回避策ですが、Mozilla 系では、DOMContentLoaded というイベントがあり、
要素が全部呼ばれたタイミングで起動するイベントがあります。
document.addEventListener('DOMContentLoaded', initialize, false);
これならば、より初期値が入っているような見た目を実現することが可能です。
IE ではどうするかというと、jQuery でもこうしているのですが、
doScroll が正常に実行できるかどうかを、
要素が全部読込まれたかの判定に使っているようです。
ここで initialize は、関数オブジェクトが格納された変数とします。
(function(){
if(initialize) {
try{
document.doScroll('left');
} catch(err) {
window.setTimeout(argument.callee, 0);
return;
}
initialize();
}
})();
function にしている理由をあらためて書いておきますが、
argument.callee でリトライする処理の範囲を決めておくためです。
doScroll に失敗した場合、catch で argument.callee が実行されるわけですが、
argument.callee = function で囲まれた部分と解釈してください。
また、画面構成によっては、onLoad が先に処理が終わってしまう場合があるそうなので、
以下のようなコードを入れておくと、より高速な処理ができると思います。
document.onreadystatechange = function() {
if (document.readyState == 'complete') {
initialize();
// doScroll の処理を実行しないようにするため、変数を無効化する
initialize = null;
}
};
要素が全部読込まれた後に実行させたいメソッドを定義するとき、
よくあるのは onLoad イベントで記述すると思います。
<body onload="javascript:initialize()">〜
または
// IE
if(document.attachEvent)
document.attachEvent('onload', initialize);
// Mozilla
if(document.addEventListener)
document.addEventListener('load', initialize, false);
onLoad イベントは、画像などのファイルが全部読込まれてから起動しますので、
イベント内で初期値を設定している場合、画面が表示されてから
勝手に入力項目に値が入ったような印象を受けます。
見た目も、ううむ、と考えさせられてしまいます。
回避策ですが、Mozilla 系では、DOMContentLoaded というイベントがあり、
要素が全部呼ばれたタイミングで起動するイベントがあります。
document.addEventListener('DOMContentLoaded', initialize, false);
これならば、より初期値が入っているような見た目を実現することが可能です。
IE ではどうするかというと、jQuery でもこうしているのですが、
doScroll が正常に実行できるかどうかを、
要素が全部読込まれたかの判定に使っているようです。
ここで initialize は、関数オブジェクトが格納された変数とします。
(function(){
if(initialize) {
try{
document.doScroll('left');
} catch(err) {
window.setTimeout(argument.callee, 0);
return;
}
initialize();
}
})();
function にしている理由をあらためて書いておきますが、
argument.callee でリトライする処理の範囲を決めておくためです。
doScroll に失敗した場合、catch で argument.callee が実行されるわけですが、
argument.callee = function で囲まれた部分と解釈してください。
また、画面構成によっては、onLoad が先に処理が終わってしまう場合があるそうなので、
以下のようなコードを入れておくと、より高速な処理ができると思います。
document.onreadystatechange = function() {
if (document.readyState == 'complete') {
initialize();
// doScroll の処理を実行しないようにするため、変数を無効化する
initialize = null;
}
};
posted by FJT at 07:08| javascript
2012年06月18日
synchronized
java は並列処理を基本としていますが、
vbscript や javascript のスクリプト言語に使い慣れている人にとっては、
慣れない概念だと思います。
ロギング処理を開発しているときに、ありえない順番でログが出ていました。
原因を調べてみたところ、複数のプロセスからログアクセスをしていて、
いろいろなログが織り交ざっていました。
ひとつのプロシージャーで、他のプロセスを気にせずに処理を行なう場合、
メソッドに synchronized を指定します。
public synchronized void test(){
}
synchronized を指定したメソッドは、処理中には他のプロセスから処理が入ることはありません。
しかし、本来並列処理を想定しておくべきです。
並列処理を想定できるかどうかは、プログラムの組み方次第だと思います。
vbscript や javascript のスクリプト言語に使い慣れている人にとっては、
慣れない概念だと思います。
ロギング処理を開発しているときに、ありえない順番でログが出ていました。
原因を調べてみたところ、複数のプロセスからログアクセスをしていて、
いろいろなログが織り交ざっていました。
ひとつのプロシージャーで、他のプロセスを気にせずに処理を行なう場合、
メソッドに synchronized を指定します。
public synchronized void test(){
}
synchronized を指定したメソッドは、処理中には他のプロセスから処理が入ることはありません。
しかし、本来並列処理を想定しておくべきです。
並列処理を想定できるかどうかは、プログラムの組み方次第だと思います。