ゆの in JavaScript 1.82008年07月10日 08時52分

アニメひだまりスケッチを 2 話で切ってしまった私が通りますよ。

String.prototype
      .\u306F\u3088\u3044\u4F5C\u54C1\u3067\u3057\u305F =
        function () this.substring(0, 4);
var o = 0;

var X = {
  valueOf: function () {
    var _ = arguments.callee.caller;
    _._ += "スケッチブック ~full color's~".はよい作品でした (o^_^o);
    _._ += _.arguments[0];
    return (this.valueOf = function () 0)();
  }
};

_.valueOf = function () {
  this.valueOf = function () Infinity;
  _._ = "ひだまり";
  _(365);
  alert(_._ + " " + eval(/".*?"/(_)[0]));
  return this.valueOf();
};

+ _ ;

function _(_)

X / _ / X < "来週も見てくださいね!"

ちなみにうちの地域では×365 は 2 日後からなんでまだ見てません。夏目友人帳と時間がかぶってるからそもそも見ないかも。

ああぁ、逃避してる場合じゃないよ。

ゆの in ECMAScript2008年07月14日 14時37分

再度ゆの in language です。この間作ったのAA 部分をプログラムの最後に置くことを優先したため、Firefox 3 以降などでないと実行できないという問題がありました。そこでこの問題を解消し、ECMAScript 第 3 版に準拠した処理系一般で (多分) 実行できるようにしてみました。ただし、ECMAScript では入出力が扱えないので、プログラム全体を評価した返り値を出力と考えることにします。

var X = {
  valueOf: function () {
    _ += "スケッチ";
    delete this.valueOf;
  },
  toString: function () {
    _ += "×365";
  }
};

ゆの.valueOf = function () {
  そんなことよりヱヴァンゲリヲン新劇場版 =
    _ + " " + eval(/".*?"/.exec(this)[0]);
};

ゆの.toString = function () {
  _ = "ひだまり";
  this();
  delete this.toString;
  return this;
};

var languageが流行ってるって = { undefined: true };

function ゆの() {
  X / _ / X < "来週も見てくださいね!";
}

ゆの in languageが流行ってるって?
そんなことよりヱヴァンゲリヲン新劇場版:破はまだですか?
早くカヲル君が見たいです.
ヱヴァンゲリヲン新劇場版:序でカヲル君が出てきたときは (以下省略);

ちなみに私は勝手に次の二つの制約を加えています。

  1. 「ひだまり」「スケッチ」「×365」「来週も見てくださいね!」という文字列はソース文字列中にそれぞれ一度しか現れない。
  2. AA 部分を評価する。

動作の解説を公開しました。

Shibuya.js in Kyoto 発表資料「取説 正規表現」2008年07月21日 12時08分

オープンソースカンファレンス 2008 Kansai 内のセッション、Shibuya.js in Kyoto に発表者として参加させていただいたので、資料を公開します。

内容は JavaScript での正規表現の基本的な扱い方です。正規表現パターンの解説はよく見かけるのですが、それを実際にどう使うかという情報が不足していると感じたので、一部だけですが取り上げてみました。こちらの練習不足でぎこちないプレゼントなってしまい申し訳なかったです。

補足ですが、if ((match = re.exec(str)))while ((match = re.exec(str))) のように条件式を丸括弧でくくっているのは、それが代入式であることを強調するためです。SpiderMonkey では if (match = re.exec(str)) などと書くと、「等値比較 (==) を代入 (=) と書き間違えていませんか?」というような警告が出ます。

また、「グローバルマッチの使用例」に関して、ECMAScript 3 では同一の正規表現リテラルを評価すると、常に同じ RegExp オブジェクトのインスタンスが返ることになっています。たとえば、以下のコードで regexps[0]regexps[1] は同じオブジェクトを指します。Firefox と Opera はこれに従っています。

var regexps = [];
for (var i = 0; i < 2; i++)
  regexps.push(/.../g);

regexps[0] == regexps[1];
// Firefox, Opera => true
// IE, Safari     => false

しかし、ECMAScript 3.1/ECMAScript 4 では、正規表現リテラルを評価するたびに新しい RegExp オブジェクトのインスタンスを返すことになる予定です。この場合、while 文の条件式内で直に正規表現リテラルを書くと、ループの各回ごとに lastIndex プロパティの値が 0 で初期化された新たな RegExp オブジェクトが返るため、常に同じ位置から検索を開始することになり無限ループが発生してしまいます。これは IE、Safari の動作と同じです。

OSC Kansai ×2008 来年も来てくださいね!

Kanasan.JS JavaScript 第 5 版読書会 #52008年07月25日 11時09分

Kanasan.JS JavaScript 第 5 版読書会 #5 に行ってきました (当日のチャットログ参加者のブログ記事一覧)。今回からはいよいよ第 2 部、クライアントサイドスクリプトということで、13 章全体を読みました。

控えめな JavaScript

JavaScript をどのように使うかの指針として、「控えめな JavaScript (unobtrusive JavaScript)」(WaSP DOM Scripting Task Force の声明文) というキーワードが挙げられています。

  1. HTML マークアップと JavaScript コードを分離する。
  2. 正常に機能を停止する。ブラウザがある機能を持たない、もしくは JavaScript 自体が動作しない場合であっても、コンテンツが利用可能であるようにする。
  3. アクセシビリティを低下させるのではなく、向上させる。

これは非常に重要な指針であり、通常の Web ページでスクリプトを使う際にはぜひ従うべきものだと思います。とはいえ、文書ではなくアプリケーションを提供するときにはスクリプトの使用を必須とせざるを得ない場合もあり、悩むところです。

document.write の挿入位置

document の write メソッドで出力された内容は、多くのブラウザで script 要素の終了直後に挿入されます。仕様ではどうなっているかというと、HTML 4.01 の文書の動的変更に関する箇所 (原文) ではややあいまいながらも script 要素を出力内容で置換するように読み取れます。DOM HTML の write メソッドの定義では読み込み中の文書に対する動作が記されていません。HTML 5 のwrite メソッドの説明ではそのあたりの詳細も定義される予定です。

JavaScript の MIME タイプ

RFC 4329 Scripting Media Types では text/javascript は非推奨となっていますが、IE が application/javascript に対応していないので、当分は text/javascript を使わざるを得ないでしょう (cf. オレオレ言語の MIME タイプ)。

script 要素の defer 属性

スクリプトの実行を後回しにして、先に文書の解析を続行できることを示す属性です。実行を延期されたスクリプトは、実行を延期できないスクリプトに出くわした時点で実行されますとありますが、HTML 4.01 での defer 属性の定義 (原文) にそのようなことは書かれていません。文書の動的変更に関して、すべての SCRIPT 要素は、文書が読み込まれる際の順番で評価されるという文と組み合わせての解釈のようです。HTML 5 の defer 属性の定義では IE の実装に合わせる形で動作が再定義されています。

noscript 要素

「控えめな JavaScript」の考え方に従うなら、noscript 要素を使わなくてもスクリプト無効時の閲覧に支障が出ない文書の作成を目指すべきだと思います。

document.domain

通常、ドメインの異なるページ間ではオブジェクトにアクセスできませんが、アクセスする側される側とも document の domain プロパティに同じ値を設定することで、アクセスできるようになるそうです。ただし、domain プロパティに設定できるのは範囲を広げる方向のみ、つまり、www.example.org のページでは example.org には設定できるけど example.com はだめとのこと。使ったことのないプロパティなので動作もよく知りませんでした。

Same Origin Policy

異なるリソース間でのアクセスで重要となってくる same origin policy、サイ本や竹迫さんのプレゼンでは「同一出身ポリシー」と訳してましたが、私は「同一生成元ポリシー」という訳語を使っています。ちなみにこれを書いている時点でググってみると、「同一出身ポリシー」203 件に対して「同一生成元ポリシー」359 件でした。

プライベート変数の実現方法

KIMOTO さんによる LT。JavaScript で、外部からは見えないが、同じクラス (便宜的にこの語を使います) のインスタンス間では見えるプライベート変数を実現する試みです。コードは次のような感じでした (一部改変)。

var namespace = {};

(function () {
  var seed = 0;
  var p = {};

  namespace.Foo = function (x) {
    var id = "" + seed++;
    this.toString = function () { return id; };

    p[this] = {};
    p[this].x = x;
  };

  namespace.Foo.prototype.getX = function () {
    return p[this].x;
  };

  namespace.Foo.prototype.setX = function (x) {
    p[this].x = x;
  };

  namespace.Foo.prototype.add = function (that) {
    p[this].x += p[that].x;
  };
})();

これなら p は外部から見えないので、アクセサを通さないとメンバ変数にアクセスできないというわけですね。コンストラクタ内でメソッドごとにクロージャを作る方法と違って、メソッドが増えてもインスタンス生成の時間はそれほど変わらないし、ほかのインスタンスのメンバ変数にも直接アクセスできます。この仕組みを考えた後に調べて、これが Perl では inside-out object と呼ばれる手法だと知ったとのことですが、それを自分で考え付いてJavaScriptで実現したというのはすごいです。

Perl の inside-out object との違いとして、JavaScript にはデストラクタがないため、メンバ変数の値がずっと残りっぱなしになってしまうという問題があります。対策としては、自分で後片付け用のメソッドを呼んでやるか、利用者のマシンの性能を信じるかといったところでしょうか。toString メソッドを本来の目的で使えないという声もありましたが、そこは代わりに valueOf メソッドを使って p[+this].x とするのもありかもしれません。

ゆの in ECMAScript 解説

いつまでそのネタを引っ張るんだといわれそうですが、私も LT の時間をもらってゆの in ECMAScript の解説をしてきました。資料は次に挙げますが、これはソースコードそのものの解説というより、ソースを読むに当たっての基礎知識です。

識別子に使える Unicode 文字の「文字」というのは letter であり character ではありません。つまり、記号や空白文字は使えません。正規表現オブジェクトの exec メソッドについては取説 正規表現を参照してください。また、SpiderMonkey では関数を文字列化したときに一部の文字がエスケープされます。

(function () { return "日本語"; }).toString();
// => function () {
// =>     return "\u65E5\u672C\u8A9E";
// => }

以上を踏まえて処理の流れを追っていくと以下のようになります。

  1. ゆの in languageが流行ってるってを評価する。
  2. ゆの.toString() が呼び出される。
  3. グローバル変数 _ を作り、値 "ひだまり" を設定する。
  4. ゆの() を呼び出す。
  5. X.valueOf() が呼び出される。
  6. グローバル変数 _ の値に "ひだまりスケッチ" を設定する。
  7. X / _undefined / "ひだまり" より NaN / NaN となり NaN に評価される。
  8. X.valueOf() が呼び出される。X 自身はもはや valueOf メソッドを持たないので、Object.prototype.valueOfX 上で呼び出され X が返される。
  9. X はプリミティブ値ではないので、X.toString() が呼び出される。
  10. グローバル変数 _ の値に "ひだまりスケッチ×365" を設定する。
  11. NaN / XNaN / undefined より NaN / NaN となり NaN に評価される。
  12. NaN < "来週も見てくださいね"NaN < NaN となり false に評価される。
  13. ゆの.toString() の結果としてゆのを返す。
  14. ゆのはプリミティブ値ではないので、ゆの.valueOf() が呼び出される。
  15. exec メソッドの引数としてゆのを渡したので、ゆの.toString() が呼び出される。ゆの自身はもはや toString メソッドを持たないので、Function.prototype.toStringゆの上で呼び出されゆののソース文字列が返される。
  16. ソース文字列がエスケープされる実装のために、引用符ごと抜き出して eval 関数で目的の文字列に戻す。
  17. グローバル変数そんなことよりヱヴァンゲリヲン新劇場版を作り、値 "ひだまりスケッチ×365 来週も見てくださいね!" を設定する。
  18. ゆの in languageが流行ってるってundefined in { undefined: true } より "undefined" in { "undefined": true } となり true に評価される。
  19. true ? そんなことよりヱヴァンゲリヲン新劇場版 : 破は...そんなことよりヱヴァンゲリヲン新劇場版となり "ひだまりスケッチ×365 来週も見てくださいね!" に評価される。式破は... は評価されない。
  20. プログラム全体の結果として "ひだまりスケッチ×365 来週も見てくださいね!" が返される。

「ゆの in language」という言葉を式中に含めたかったので in 演算子を使ったのですが、in 演算子は真偽値しか返せません。そこで、文字列を返すために条件演算子を使い、in 演算子はその条件式に含めることにしました。破は... (以下省略) の部分は評価されませんが全体としては条件演算子になっており、早くカヲル君が見たいです. ヱヴァンゲリヲン新劇場版はプロパティアクセスとして、序でカヲル君が出てきたときは (以下省略) は関数呼び出しとして解析されます。

条件演算子を使う以上コロンが必要なのですが、タイトルにコロンの入ったアニメ / マンガ / ライトノベルがヱヴァくらいしか思い浮かばなかったのでそれを使いました。後から FF:U があると教えてもらったりJINKI:EXTEND なんてものもあったなと思い出したりしたのですが、両方とも見てないのでそのままです。

雑感

個人的な反省点として、LT の時間を超過しない、発言するときは大きな声でというのが挙げられます。LT に関しては OSC Kansai 2008 閉会式の LT のように全員にわかるタイマーがあるといいのですが、それはスクリーンが二つ以上ないと難しいので、せめて秒読みをつけたほうがいいかもしれません。時間が不定なら減算式ではなく加算式の秒読みでもあるとしまりが出るかなと思います。気軽に話せるという点からすると逆効果になってしまうかもしれませんが。

全体では前日の Shibuya.js in Kyoto からの流れで竹迫さんamachang さん、それに名古屋の JavaScript 勉強会 DeLLa.JS の主催者 issm さんといった豪華メンバーが駆けつけてくださり、読書会、LT、懇親会いずれも大いに盛り上がりました。Kanasan さんはじめスタッフ、参加者の皆さんありがとうございました。ちなみに DeLLa.JS 次回は 8 月 2 日に開催予定とのことなので、名古屋圏の方もそうでない方もぜひ参加してみるといいと思います。