このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

JavaScriptのクラスもどき

しょうこりもなくJavaScript。([2005-08-08に追記]:コメントも読んでくださいね。

JavaScriptによるオブジェクト指向プログラミングに関しては、例えば、(古い記事ですが)石井勝さんによる解説などがあります。基本は、コンストラクタ関数を定義することをクラス定義とみなすことです。ちなみに、コンストラクタ関数Foo()は普通の関数に過ぎません。new Foo();の形で呼び出されると、JavaScript言語処理系が呼び出しオブジェクト(昨日の投稿を参照)のthis変数に新しく作ったプレーンな(何の特徴もない白紙の)オブジェクトをセットしてくれます。それだけのこと。

さて、上記記事によれば、クラスFooのメソッドは、いったん _Foo_doSomethingという大域関数として定義して、コンストラクタ内でthisにセットするようになっています(下を参照)。([追記]: 石井勝さんの記事では、コンストラクタ関数のprototypeにメソッド関数をセットしています。以下のコードは、僕が他のサンプルと混同していたようです。また、function式を使う方法も、同記事内の注釈として記述されています。僕の文面が杜撰<ずさん>でした、ごめんなさい。)


function _Foo_doSomething() {
// do something
}
function Foo() {
this.doSomething = _Foo_doSomething;
// ...
}

/* 使うとき */
var foo = new Foo();
foo.doSomething();

しかし、これだと大域記号空間を汚すし、ソース上で、メソッドがクラス(コンストラクタ関数)内部に配置されないので、function式を使って書いたほうが良いような気がします。ダミーのサンプルだと面白くないでしょうから、ブラウザで動く(と思われる(が、全然保証しない))例を以下に。


/* window.openをラップしたユーティリティ関数(これは大域的) */
function createWindow(name, properties, content) {
var win = window.open("", name, properties);
win.document.open();
win.document.write(content);
win.document.close();
return win;
}

/* コンソールを実現するクラス(のようなもの)*/
function Console(name) {
/* 定数:必要に応じてソース上で書き換える */
this.WINDOW_SIZE = "width=400,height=400";
this.STYLESHEET = "body {background-color:black; color:white;}";
/* フィールド */
this.name = name;
this.win = null;
/* プライベート(のつもりの)メソッド */
this._createConsoleWindow = function() {
var windowProps =
this.WINDOW_SIZE +
",toolbar=no,location=no,directories=no,menubar=yes," +
"scrollbars=yes,resizable=yes";
var title = "console:" + this.name;
var windowContent =
"<html><head><title>" +
title +
"</title>" +
"<style>" + this.STYLESHEET + "</style>" +
"</head><body><pre id='console'>" +
title +
"<br></pre></body></html>";
return createWindow(this.name, windowProps, windowContent);
};
this._print = function(message, needsNewline) {
var windowCreated = false;
if (!this.win) {
this.win = this._createConsoleWindow();
windowCreated = true;
}
var doc;
try {
doc = this.win.document;
} catch(e) {
alert("Console window might be closed.\nReload please.");
return;
}
var consoleElement = this.win.document.getElementById("console");
var text = doc.createTextNode(message);
consoleElement.appendChild(text);
if (needsNewline) {
var br = doc.createElement("br");
consoleElement.appendChild(br);
}
if (!windowCreated) {
this.win.focus();
}
};
/* パブリック(のつもりの)メソッド */
this.print = function(message) {
this._print(message, false);
};
this.println = function(message) {
this._print(message, true);
};
} // クラスもどき、ここでオシマイ

var out = new Console("out");のように、適当な変数にConsoleオブジェクトを入れておけば、out.print("Hello, "); out.println("world.");のように使えます(たぶん)。コンソールウィンドウが手で閉じられたときの対策が全然手抜きですが、カンベン。

このスクリプトを含んだHTMLサンプルはコレ

[追記]:もう(?)、JavaScriptなのかもな」とふと思って調べはじめて3日くらい。なので、僕よくわかってないかも。わかった(と思えた)事を記録しているだけなので、なにか勘違いがあるかもしれません。まっ、browser-based RIAについてはもう少し調べる価値があるとは思ってますが。