呼ばれていないけど、私もコードゴルフしてみました ― 2013年08月09日 03時06分
Code 2013 というイベントで出されたというコードゴルフのお題「JavaScript でデジタル時計」を見ているうちに、自分でもやりたくなったので挑戦してみました。
基本方針
出力が複数行にわたるなら 1 行ずつ処理していくのが素直な手ですが、このお題においてはそれだとひとつの文字に対する処理が細切れになってしまいます。
そこで、ある文字の出力処理をまとめてやってしまいましょう。行ごとにではなく列ごとに処理を進めていくのです。
20 分
方針が決まれば早速コーディング。以前、渋谷から 10 分のゴルフ場
で似たようなお題「banner」に取り組んだときは三十六進数表記を使いましたが、とりあえずは読み書きしやすいよう二進数表記で進めます。
本番の制限時間は 20 分だったそうなので、こちらも 20 分で到達したところはこちら、
t = 0;
setInterval(function () {
s = ' ■';
p = [
'111111000111111',
'111110000000000',
'111011010110111',
'111111010110101',
'111110010011100',
'101111010111101',
'101111010111111',
'111111000010000',
'111111010111111',
'111111010111101',
'000000101000000',
].map(function (b) { return parseInt(b, 2) });
l = ['', '', '', '', ''];
d = [
t / 60 / 10 | 0,
t / 60 % 10 | 0,
10,
t % 60 / 10 | 0,
t % 60 % 10 | 0,
];
for (i in d) {
v = p[d[i]];
for (j = 20; j--;) {
l[j % 5] += s[v & 1];
v >>= 1;
}
}
document.body.innerHTML = l.join('<br>');
t++;
}, 1000);
スペース・改行を取り除いて 458 バイト (UTF-8 でエンコードした場合) と、ちょっと詰めきれていません。二進数表記文字列 + map
メソッドの組み合わせを十進整数リテラルに書き換えるだけで 284 バイトになるので、あと一歩ではあったのですが。
改良
このお題ではひとつの文字を表すのに、3 列 5 行、15 個の点を使っています。ひとつの文字に対するパターンが 15 ビットで表現可能ということは、JavaScript の 1 文字 (16 ビット) に収まるわけですね。
ほかにも、変数 s
、p
はそれぞれ 1 箇所でしか使っていないので、変数を使わずリテラルを直接書くといった節約の成果がこれです。
t = 0;
setInterval(function () {
l = ["", "", "", "", ""];
for (i in d = [t / 600, t / 60 % 10, 10, t % 60 / 10, t++ % 10])
/* "\u7E3F\u7C00\u76B7\u7EB5\u7C9C\u5EBD\u5EBF\u7E10\u7EBF\u7EBD\u0140" */
for (v = "縿簀皷纵粜庽庿縐线纽ŀ".charCodeAt(d[i]), j = 20; j--; v >>= 1)
l[j % 5] += " ■"[v & 1];
document.body.innerHTML = l.join("<br>")
}, 1e3)
スペース・改行を取り除いて 230 バイトまで減らせました。さらに、setInterval
の第 1 引数を関数ではなく文字列にすることで、220 バイトとなります。
上述の版では文書読み込み完了から 1 秒間が空いて時計の描画が始まります。サンプルと同じく文書読み込み完了と同時に時計が描画される、修正版 (229 バイト) を作りました。v >>= 1
を v /= 2
にするという変更も入れています。
追悼 E4X (仮) 発表資料 ― 2013年05月27日 21時49分
Firefox 21 で E4X のサポートが削除されたのを受け、「追悼 E4X (仮)」というイベントが開催されました。東京での開催だったのですが、私自身仕様の邦訳を手がけるなど E4X には並々ならぬ想いがあり、京都から駆けつけた次第です。
来たからにはと私も「E4X と autovivification」という題で LT をしてきました。Perl でいうところの autovivification という機能が E4X にも備わっているという話です。ほかに「私と E4X」という発表 (むしろ自分語り) もしたのですが、こちらはその場限りのオフレコです。
追悼というだけあって皆さん E4X に対する熱い思いを語っていましたが、特に感心したのが Vimperator の対応の話です。それまで E4X を使っていた部分を、ECMAScript 6 での採用が検討されているテンプレートリテラルに置き換えたものの、それ自体現在の SpiderMonkey では実装されていません。そこで、chrome://liberator/....js
と JavaScript ファイルを読み込んでいたのを、liberator://....js
と独自プロトコルを介した読み込みに変更し、そのプロトコルハンドラの中でソースコード変換を行っているとのことでした。
私も製品のコード中で E4X を使っており、結果として後進に負の遺産を残すこととなってしまったのですが、一方で E4X があったから今の私があるというのもひとつの真実であり、E4X 仕様及びそれを実装した Mozilla に深く感謝します。
jQuery のバグを見つけてから修正されるまで ― 2013年01月28日 02時17分
1 月 24 日に開催された Kyoto.js meetup 4 で「jQuery のバグを見つけてから修正されるまで」と題した発表を行いました。
jQuery へのコミットに関して 2 行でまとめるとすれば次のようになるでしょうか。
- jQuery のソースコードはショートコーディングの嵐なので心してかかる
- Contributing to jQuery と jQuery Core Style Guidelines は必読
発表の筋書きは以下の通りです。
jQuery のバグを見つけてから修正されるまで
フォロー・ミー
- nanto_vi (TOYAMA Nao)
- 株式会社はてな アプリケーションエンジニア
- クライアントサイド (JavaScript)
- サーバーサイド (Perl)
- jQuery をバリバリ使っている
- Deferred
- イベント
- DOM 操作
ある日どこかで
街中にクリスマスの装飾が灯り始めるころ
うんうん、変わったよね
…
……
そういえば Deferred
を使ったとき this
の値はどうなるんだったっけ?
$.Deferred().done(function () {
this // ← ココとか
}).then().done(function () {
this // ← ココの値は?
});
jQuery 1.8.3 と jQuery 1.9 Beta 1 で結果が違う!
汚れなき悪戯
- #11405 (deferred.notify() invokes progressCallbacks with deferred as context) -- jQuery Core - Bug Tracker
- Deferred: .resolve(), .reject() and .notify() now set the callback conte... · 23d7cf0 · jquery/jquery
ふむふむ…… (コードを読む)
ふむふむ…… (コードを読む)
ふむふむ…… あれ?
これ、自分の書いたコードが動かなくなる?
$.Deferred().then(function () {
// ここでの this が
return $.Deferred().resolveWith(this, arguments);
}).done(function () {
// ここにも引き継がれてほしい
this
});
……
まずい!
バック・トゥ・ザ・フューチャー
- https://github.com/jquery/jquery/blob/1.8.3/src/callbacks.js
- https://github.com/jquery/jquery/blob/1.8.3/src/deferred.js
- https://github.com/jquery/jquery/blob/1.9.0b1/src/callbacks.js
- https://github.com/jquery/jquery/blob/1.9.0b1/src/deferred.js
どこを直せば自分のコードが動くのか
コードとにらめっこ
にらめっこ
にらめっこ
……
問題なのはここ、でもここを変えると先の変更の意味が失われるから……
こことここか!
羊たちの沈黙
直すならテストを書かないと
テストを書くならテストを走らせないと
テストを走らせるなら jQuery のビルド環境を作らないと
grunt
? Node.js なら入ってるし楽勝でしょ
……
うわあ、この Node.js バージョンが古い!
うわあ、この OS バージョンが古い!
うわあ、この Python (ry
……
沈黙
そしてクリスマスが過ぎ、正月が過ぎた
風と共に去りぬ
やっぱり正月松の内は休まないとね
ってなになに……
げげー、1.9-stable
ブランチ!
もはや一刻の猶予も許されない
禁じられた遊び
俺にはこの SpiderMonkey JavaScript Shell がある!
秘技、テストのコピペ改変!
荒野の用心棒
「これ直さへんとあかんちゃう?」
J 「プルリクエストにしてーな」
「プルレクったでー」
D 「ここ冗長やろ。もっと削れるやろ」
(そない言われても…… これ以上どう切り詰めろいうんや……)
(しゃあないな、この条件分岐をもっと前に持ってきて……)
(あれ、この変数、フラグに流用できるちゃうか……)
「どや!」
D 「まあええんちゃうか」
素晴らしき哉、人生!
D 「修正取り込んだで。おーきに」
J 「僕と契約して貢献者になってよ!」
めでたしめでたし
※ この物語は実話を基にしたフィクションです。
jQuery で HTTP 接続するときの書き方 ― 2012年12月16日 19時41分
12 月 13 日に Kyoto.js の第 3 回 meetup で、「jQuery で HTTP 接続するときの書き方」と題した 5 分間のライトニングトークを行いました。以下にその内容を一部再構成して収録します。
こんにちは、nanto_vi です。今日は jQuery で HTTP 接続をするときの書き方について話します。
皆さん jQuery を使うことも多いかと思います。jQuery で HTTP 接続をするとき、古いサンプルだと次のような書き方が載っています。
$.ajax({
url: '/foo/bar',
data: { baz: 'qux' },
success: function (data) {
console.log(data);
},
});
接続完了時の処理をコールバック関数として $.ajax()
に渡してやる形ですね。しかし、現在この書き方は非推奨となっており、替わりに次のようにも書きます。
$.ajax({
url: '/foo/bar',
data: { baz: 'qux' },
}).done(function (data) {
console.log(data);
});
$.ajax()
の返り値に対して、done
メソッドで接続完了後の処理を登録する形です。この書き方の何がいいかといえば、返り値を使いまわしたり done
メソッドを複数回呼び出したりして、完了後の処理を後から追加できるところです。昔の書き方では完了後の処理がコールバック関数として $.ajax()
の内部に格納されていましたが、現在は「完了後の処理」だけを $.ajax()
の外部に (「プロミス」として) 取り出すことが可能になったわけですね。
今「内部の処理を外部に取り出す」と言いましたが、この言葉はどこかで聞き覚えがありませんか。そう、内部イテレータと外部イテレータです。
内部イテレータは、オブジェクトが個々の要素に対する処理を受け取り、オブジェクト内部で自身の各要素に適用させる形、
// 内部イテレータの使用例
$('p').each(function () {
doSomethingWith(this);
});
外部イテレータは、オブジェクトから「各要素を列挙する」という機能だけをオブジェクト外部に取り出す形です。
// 外部イテレータの実装例と使用例
$.fn.iterator = function () {
var i = 0, n = this.length, self = this;
return {
hasNext: function () { return i < n; },
next: function () { return self[i++]; }
};
};
var iterator = $('p').iterator();
while (iterator.hasNext()) {
var element = iterator.next();
doSomethingWith(element);
}
JavaScript 1.7 以降ではジェネレータという機能により、内部イテレータのような書き方で外部イテレータを生成することができます。
さて、「処理を内部に持ってしまっている」というのは、イベントハンドラの登録も同じですね。
$(document).on('click', function (event) {
...
});
イベント発生時の処理をコールバック関数として jQuery オブジェクト内部に渡していますが、これを外部に持ち出すことはできないのでしょうか。
実はそれを可能にするものとして Reactive Extensions (Rx) があります。Rx 入門記事の図にもあるように、Rx を使うと空間にまたがる要素 (配列など) の列挙と時間にまたがる要素 (イベントなど) の列挙を統一的に扱うことができます。
Reactive Extensions は主に .NET Framework 上で利用されていますが、JavaScript での実装として RxJS が公開されています。
- neue cc - linq.js & Reactive Extensions for JavaScript(RxJS)入門
- neue cc - Reactive Extensions入門 + メソッド早見解説表
- Rx (Reactive Extensions) - Home
ObserverパターンとIteratorパターンは同じだったんだよ!なんだってー!
そう、ObserverパターンとIteratorパターンは同じなのだよ、ナンダッテー!
(このあたりで時間切れ)
IE 6/7 で文書間通信を実現するための一案 ― 2011年12月08日 23時32分
HTML5-WEST.jp 飲み会 UST というのがあるそうで、「参戦希望者募集」とお誘いを受けたのですが、「参戦」というからには何かしら戦の準備を整えねばなるまいと、以前から考えていたことを夜なべして実装しました。
いわゆる HTML5 の文書間通信、window.postMessage()
を IE 6/7 でどう再現するかという話で、about:blank
を指す隠しフレームを二つ用い、window.name
を介することで双方向の通信を実現しています。
どうも IE での about:blank
は、その空白ページを読み込ませた文書の生成元を継承するらしく、たとえば http://example.org/
から location.href = 'about:blank';
を実行すれば http://example.org
を生成元とする about:blank
になります (少なくともそのように見えます)。これを利用し、一つのフレームに二つの文書から交互に about:blank
を読み込ませあうことで、そのフレームの window.name
を両文書で共有できるという仕組みです。
about:blank
を読み込ませるのに location.reload()
を使えば履歴に余分な項目を残すこともありませんし、フラグメント識別子を使った場合と違ってデータ量にもだいぶ余裕が出ます。
最近のコメント