Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Saturday, September 26, 2009

Programming::JavaScript - エラーコード800a03e8

IE8でJavaScriptの動作チェックを行っていたら、
突然、エラー 800a03e8のため止まりますみたいなことをIEが出力してきました。
800a03e8でぐぐってもほとんどヒットしないので途方にくれていましたが、
IE TesterでほかのバージョンのIEでも確認してみたところ、
きちんとしたエラーメッセージがもらえました。
(IE8でデバッガを有効にしていたからちゃんと出なかったのかな?)
下記のようなエラーメッセージが出ました。

HTML Parsing Error: Unable to modify the parent container element before the child element is closed (KB927917)

そこで落ちたら今まで動いていたコードが動かなくなるじゃん!
document.write()とかの使いどころが激減する予感。

開発しているシステムのほうではdocument.write()でdiv要素とかを出力していまして、
body要素の半ばあたりでそれやっちゃうと上記みたいに怒られる、と。
しかしながらほかのサイトでもご紹介されているとおり、
bodyのとじタグ付近だったらOKなんですよね、いみふ。
bodyのとじタグ付近だろうがなんだろうが、
上記のエラーメッセージ通りの制約を課すならアウトだろうに。
何考えてんの?IEのデベロッパーは。
とか思います。
bodyの子要素からしてみれば、bodyは書き換えてよい親なのでしょうか。

対策として、document.writeやってるところは
すべてwindowがloadし終わったあとにdocument.body.appendChild()使って
要素を追加するよう書き直すしかない、ってことなんでしょうかね。

そういえばdocument.writeやってても大丈夫な箇所も、一応あります。
bodyの子(孫とかではなく)になる要素だったらdocument.writeして
要素を追加してもよいのかも。
んで、一回のdocument.writeの呼び出しで
bodyの子、bodyの孫を一気に出力しちゃえばOKなのかな
(一気に、っていうのは孫要素のとじタグもちゃんと出力してしまうということで)。

もー世の中FirefoxとChromeだけになりませんかね、無理ですよね。ふぅ。

Monday, June 11, 2007

Programming::JavaScript - クラスの継承とオーバーライド

お遊びで作ったものですが。

JavaScript Library MKF

prototype.jsを先にscript要素で呼び出しておく必要があります。
JavaScriptでは継承がすっきりかけなくていやんだったので,
自分なりに作ってみました。
MKFを使うと継承はこんな感じです。

// スーパークラスの定義
var MySuperClass = Class.create(); // MKF.Class.create();でも可
MySuperClass.prototype = { /* ここにMySuperClassの定義を書く */ };

// サブクラスの定義
var MySubClass = MKF.Class.create();
MySubClass.extend(MySuperClass).implement({
initialize : function (arg) {
this._super(arg); // スーパークラスのコンストラクタ呼び出し
},
new_method1 : function () { /* サブクラスで新しくメソッドを定義 */ },
...
});

_superキーワードでスーパークラスのコンストラクタ呼び出しが出来るんで,
少しは気分良く継承が出来るかなぁと思っています。

そしてメソッドのオーバーライド。
普通にやろうとすると,スーパークラスのメソッドをサブクラスで上書きすることになるんですが,
そうするとスーパークラスのこのメソッドが呼び出せなくなります。
スーパークラスのオーバーライド対象となるメソッドを呼び出す前後に,
何かしら処理を加えたいとき,スーパークラスのが呼び出せなくていやんです。
なので,呼び出せるようにしてみました。

var MySuperClass2 = MKF.Class.create();
MySuperClass2.extend(MKF.Class.Overridable).implement({
initialize : function () { /* コンストラクタ */ },
calc : function (x, y) { return x + y; }
});
var MySubClass2 = MKF.Class.create();
MySubClass2.extend(MySuperClass2).implement({
initialize : function () { /* コンストラクタ */ },
// オーバーライドするメソッドをここで定義する
override : {
calc : function (x, y) {
x *= x;
y *= y;
return super_method(x, y); // MySuperClassのcalcを呼び出す
}
}
});

var foo = new MySuperClass2;
alert(foo.calc(2, 2)); // 4が表示される
var hoge = new MySubClass2;
alert(hoge.calc(2, 2)); // 8が表示される

スーパークラスのコンストラクタ呼び出しは"this._super"で"this"がついているのに,
スーパークラスのオーバーライドされた元々のメソッドの呼び出しは"this"がつかなくて
少々気持ち悪いですが。

こんなものを作ってみましたが,
JavaとJavaScriptを連携して動かす方法もあるようなので,
オブジェクト指向でしっかり書きたいところはJavaで書くべきなのかもしれませんね。

Saturday, January 13, 2007

Programming::Javascript - 少し冷静になって作ってみる

こちらで書いたとおり、 _super()でスーパークラスのコンストラクタ呼び出しが可能なのは相変わらずです。ただ、_SUPERキーワードを使ってスーパークラスのメソッドを呼び出そうという試みで、正しくスーパークラスのメソッドが呼び出されるよう_SUPER.method(arg)を字句解析を用いて探し出し、変形させてやろうとしていたのですが…計算コストが高くつくのと、何か微妙にバグがとれずにいたので、実装するのに少し萎え気味になりました。デバッグが著しく面倒ですからね、JavaScript周りは。せっかく軽量で分かりやすいライブラリを目指しているのに、字句解析とか導入して重くなるのは嫌です、やっぱり。

Core JavaScript 1.5 Guide:Class-Based vs. Prototype-Based Languagesで、プロトタイプベース言語とクラスベース言語の比較について述べてあります。まー、JavaScriptプロトタイプベースの言語なんだから、無理にクラスベースの言語の使用に近づけなくても良い、というかむしろそれは良くないんかなぁっていう気がしてきました。これを読んだからだけでなく、クラスベース言語と同じようなことをしようとして、結果的に計算コストが高くつくようになってしまったことも、このような考えに至った原因の一つですが。

計算コストは恐らく、すんごいコーダーの手に掛かればもっと削減できるのでしょうが。スーパークラスのコンストラクタ呼び出しは結構使うと思うんで、これは削除せずに置いておきます。_SUPERキーワードを使ったスーパークラスのメソッド呼び出しは、サブクラスでオーバーライドしたメソッド内で、オーバーライドされる前のメソッドを呼び出したいときなんかは重宝するかなと思ったのですが。もうちょっと他の方法を考えてみて、出来そうだったら実装してみようかなと思っています。

Monday, December 25, 2006

Programming::JavaScript - 独自のキーワードを定義する

こちらで書いた通り、_superキーワードを使うことで、スーパークラスのコンストラクタを呼び出してやろうという試みをしています。_superキーワードを利用しているメソッドの中身を、toString()によって一度文字列化して、_superをスーパークラスのコンストラクタを格納したメンバ変数名へと置き換えることで、あたかも_superでスーパークラスのコンストラクタを呼び出しているように見せかけています。

一応簡単に、正規表現を使って_superを、コンストラクタを格納しているメンバ変数名へと置換していたのですが(正確にはthis._superを置換)、まぁそりゃ無謀なので。きちんとやることにしました。きちんとやるって何をやるかといいますと、コメントや関数呼び出し等々を判別して、ここは_superキーワードを利用していると解釈した上での置換をやります。それをするためには何をしなければならないか、といいますと、字句解析です。

在ればちょっと嬉しいな、という機能のために字句解析するんかい、とか思いましたが、とりあえず実装してみます。こういう場合、オートマトンで図式化してコーディングしたほうがいいんかな?とか思いましたが、オートマトンがわやくちゃになってきたので、やっぱりゴリゴリif elseでコーディングします。

何も考えずに字句解析を用いて_superキーワード置換を行っていたら、何だか処理が重くなりました。なんと、全ての実行されるコンストラクタを字句解析していました。100回近くになるのかな?各コンストラクタのステップ数はまちまちですが。もちろん、後で不要な字句解析をカットするようにしました。

しっかし、字句解析してやると実行時にコードの改変が行いやすいので、独自キーワードの定義とか色々出来そうな気がしてきました。それをやったから何だという話ですが。ノリ的にはClass with Cみたいな言語系に出来るのかなーとか思ったりします。

Friday, December 15, 2006

Programming::JavaScript - ドキュメント生成

Doxygenのように、ソースコードにつけられたコメントからドキュメントを自動生成できれば楽なんで、JavaScript向けのドキュメント生成ツールJSDocを使ってみようと思っていました。phpDocumentorやJavaDocなどと似たような記法ができるので、さらっとJSDocのマニュアルを読んで、ソースコードにドキュメントをつけていきました。

で、昨日いざ生成してみようと思ったら。まったくドキュメントが生成されません。まったくというか、少しは生成されたのですが、こちらの意図したとおりに動いてくれてなかったようです。例えば、JSDocが期待するクラスの宣言は、

function MyClass(arg) { ... }

な訳で、方や私が用いた記法は

// prototype.jsを利用しながら
var MyClass = Class.create();
MyClass.prototype = {
initialize : function(arg) {...},
...
};
です。どうもPerlの正規表現を用いてコメントの抽出などを行っているようで、おそらく"クラス名.prototype = "が来ればクラス宣言だ、というのは無いのかもしれません(そんなにじっくり見ていないのでわかりませんが)。

きちんとドキュメント生成してほしいがために、ソースコードをドキュメント生成に適した書き方に書き換えるのは面倒です。ので、JSDocを使うことは諦めました。

Perlコードのドキュメント生成にはpod2htmlとかを使っていたので、仕方なくpodファイルを作っていくことにしました。podファイルで在れば、極端な話(?)ソースコードが無くてもドキュメント生成できますし。doxygenとかは無いとやりづらそう。まぁ、JavaScriptコード中にへたっぴな英語でコメント付けてたので、日本語に直す予定ではありましたから、podファイルをモリモリ作っていこうかと思います。

Saturday, December 09, 2006

Homepage::Update - 久しぶりのリニューアル

そろそろ飽きてきたり、DynamicHTMLを覚えたり、デザインのことを少し勉強したりと、諸事情によりトップページをリニューアルしました。今回は、画像を使わずにどんなデザインで表現できるか?というのをテーマにしてみました。矩形は簡単に表現できますが、斜めのラインや楕円、三角形などは表現できませんね...何か上手いやり方が在るのかも知れませんが。

トップページ上に情報をモリモリ書きたくなかったので、どこがポイントやな?って話になりますが、左サイドの装飾と、左クリックによるポップアップメニュー、そしてそれらにかけられる影のエフェクトでしょうか。プログラム的には、裏でクラスの継承やらをちょっといい感じに自前で実装してたりします。サブクラスのコンストラクタ内で
this._super();

とやれば、スーパークラスのコンストラクタが呼ばれるようにしています。継承するたびに、各スーパークラスのコンストラクタを保存していき、_superで正しいコンストラクタを呼び出せるようにしないといけない箇所がちょっと大変でしたが。

つまり、クラスAのスーパークラスがBで、BのスーパークラスがCだとしておきますと。
// prototype.jsのClass.create()使っているのでinitialize
B.prototype["_super"] = C.prototype.initialize;

として置き、B.prototype.initialize内で
this._super();

を呼ぶとします。Bを継承してAを定義したときに、
A.prototype["_super"] = B.prototype.initialize

として、A.prototype.initialize内で
this._super(); // これはB.prototype.initializeだが...

を呼びます。B.prototype.initialize内でもthis._super()を呼んでいるわけですが、この_superはA.prototype._superの事になってしまっているので、再びB.prototype.initializeを呼んでしまい...無限ループになります。

これを回避するために、FunctionクラスのtoStringメソッドでソースへ落とし込み、_super()を_super0()というように重複しないように書き換えます。もちろん、B.prototype["_super"]にクラスCのコンストラクタを代入するのではなく、
B.prototype["_super"+B.__INHERITANCE_NUMBER] = C.prototype.initialize;
// B.__INHERITANCE_NUMBER = 0

としてやります。この__INHERITANCE_NUMBERは継承回数-1としておき、継承を行うたびにカウントアップしていけば、_superが書き換えられずにきちんと保存されているように見えます。

ソースコードへ落とし込んだ後、Firefoxではeval()してやれば関数オブジェクトを返してくれたのですが、IEでは何も返してくれません。だもんで、無名関数を定義して、そのなかで上記のthis._super0の中身を実行するようなevalを書いてやらなければなりませんでした。この無名関数を、B.prototype["_super0"]に代入してやればOKです。

スーパークラスが何かが分かっているんだから、いちいち_superを自動で定義してやらなくても、手で書けばいいじゃないか、という話になるのですが、こっちの方がエレガントかなぁとか思いまして(笑)変数(名)がクラス(名)のように扱われるので、
var D = C;

とやれば、C言語でいうtypedefが簡単に出来てしまいます。ので、スーパークラスのコンストラクタ呼び出しも、上記のようにスーパークラスに別名をつけるような処理を行っておけば、長いクラス名でも手で打つのは全然面倒ではありません。

まぁ、あくまで自己満足と勉強のためにわざわざ、スーパークラスへのアクセスキーワードを定義したりしているわけです。JScriptだったらsuperキーワードが定義されていたような気も。

ちなみに現在は、スーパークラスのコンストラクタ呼び出し以外にも、スーパークラスのメソッド呼び出しも可能にしたいとか思っておりまして。overrideしたメソッドから、overrideされた元々のメソッドを呼びたい時に、Perlみたく、$obj->SUPER::method()と書きたいわけでして。Firefoxだったら動くのにIEだと動かない!という状況に再び遭遇したので、もう少しこの問題と格闘しそうです。

Friday, December 01, 2006

Programming::WebApplication - JavaScript UI Libraryたち

バイト先で重宝しているprototype.js。コレなどを用いるとクロスブラウザなJavaScriptコードが書きやすく、リッチなユーザインターフェースを実現することも割と容易になってきます。

現在サイトのトップページをリニューアルしようと思って、ついでにちょっとだけJavaScriptによるリッチユーザインターフェースライブラリでも作ろうと思い、作り始めました。と、その前に、今ユーザインターフェースライブラリはどれくらい在るんだろうと思って調べてみると。こちらにリンクがまとめてあり、参考になりました(あるSEのつぶやき - Ajaxライブラリまとめ)。まだまだ日本製は少ないわけですが、それにしても豪華な演出をするライブラリがたくさんありますね。ま、正直それはやりすぎでうざいな、っていうのも在るわけですが、そこんとこは好みの問題。あまりネイティブGUIアプリケーションのようなインターフェースに近づきすぎるのもいかがなものかと私は思ったりします。が、ものによっては便利ですよね。今バイト先で作っている事務的なWebアプリなんかだと、こういうリッチインターフェースだと操作性が良くなったりしますし。

別にこれらに対抗しようというわけではありませんが、勉強がてら、私好みの演出が出来る、軽量なユーザインターフェースライブラリを作っていきたいと考えています。ちなみに今できているのは、
  • Windowクラス(MKF.Window)
  • ContextMenuクラス(MKF.Window.ContextMenu)
    • MKF.Windowを継承
  • Timerクラス(MKF.Timer)
    • 有限時間内で一定間隔に任意の関数を実行するオブジェクト指向タイマー
  • 画面効果クラス(MKF.Effect)
    • 任意のDOMオブジェクトの透過度を変化させることにより、フェードイン、アウトさせる
MKF.Window.ContextMenuを要素に関連づけて、その要素上でクリックしたら作製したコンテキストメニューを表示させる。この処理ができて、トップページのレイアウトを少し変更したら、トップページを差し替えようかなとか思います。

Sunday, November 12, 2006

Programming::JavaScript - 自前ウインドウライブラリ

Bloggerのベータ版に移行してみると、あれこれ変更が在るのに目がいきつつも、過去の投稿データが微妙に移行し切れていないのに歯がゆさを覚えつつあります。

それはそれとして、 ブラウザ上で仮想デスクトップを実現するeyeOSに大変感化された私は、どうにもこうにもブラウザ上でウインドウアプリケーションを実現したくてたまらなくなってきました。

探せばウインドウアプリケーションを作るためのJavaScriptライブラリはあるだろうと思ったのですが、今日探した限りでは特に見つからず。ZKはかなり良さそうだったのですが、Java Servletを使うんかい、と思ってあまりつかう気になれなくなってしまいました。

覚えることが大量に増えず、(サーバ、クライアント両方に対して)軽く、使いやすいものって…と思っているとなかなか見つからず。Drag And Dropに対応だとか、そういうなのはあるんですけどね、たくさん。

Prototype.jsがあれば、割と簡単に自前ウインドウライブラリは作れるんじゃなかろうか、と思い始め、本来の作業目的とはずれつつも、ライブラリ作成に没頭してしまいました。とりあえず、タイトルバーをドラッグすればウインドウもつられて移動し、ウインドウの表示、非表示、サイズと位置変更くらいは出来るようにしておきました。ウインドウの閉じるボタンとかもつけたいな、と、色々やりたいことは湧いてきます、ホント。