怖話では怖い話をサウンドノベル風に表示するのに色々端折ると下記のようなJavascriptを実行しています。

var text = ["こ", "わ", "い", "は", "な", "し"];
setInterval(function(){
  line.innerHTML += text.shift()
}, 80);

これが、PCやiPhone(3GSとかでも)ならばいいんですが、Androidのブラウザーだと僕の持っているGalaxy Nexusでもかなりカクカクします。

innerHTMLが遅いっていうのはよく見るんですが、全部つないで最後に表示というものではなく、実際に一文字、一文字増えていくサウンドノベルみたいな表示をするときに他の方法がイマイチわかりません。何か詳しい人だったら一発で速くなりそうな気もするんですがなんとも…。

iOS Simulator - iPhone / iOS 4.3 (8F192)

Write below If you want to hide address bar on iPhone or Android.

window.scrollTo(0, 1)

ClojureでJavascriptが書けるClojureScriptが発表されました。(via Clojure/core — Introducing ClojureScript)

と思いかけましたが要はCoffeeScriptと同じアプローチで、

「オブジェクト指向なCoffeeScriptの代わりに関数型言語のClojure(ClojureScript)でJavascript書けるよ」

ということのようです。

とはいえClojureScriptはClojureの完全なJS実装というわけじゃなくて、JVMやJavaコアライブラリに依存してるところも多いので、Pure Clojureなら大体動く予定という感じのようです。

JavascriptとなるとGoogle Closureと名前が紛らわしいわ!という問題は承知してるそうですが、ClojureScript自体がGoogle Closure(Library, Compiler)に依存してるのでややこしいです。

インストール

% git clone git://github.com/clojure/clojurescript.git
% cd clojurescript
% script/bootstrap

ClojureScriptはClojureとJavascriptで書かれてるのでJava 6が必要です。(JavascriptにはRhinoがある)

REPL

% script/repljs
#'user/jse
"Type: " :cljs/quit " to quit"
ClojureScript:cljs.user> (println "foo")
foo
nil

Javascriptへのコンパイル

;; hello.cljs
(ns hello)
(defn ^:export greet [n]
  (str "Hello " n))
% bin/cljsc hello.cljs '{:optimizations :advanced}' > hello.js
;; hello.js
function b(c){throw c;}var f=null;function aa(){return function(c){return c}}function i(c){return function(){return this[c]}}function j(c){return function(){return c}}var k;
function n(c){var a=typeof c;if(a=="object")if(c){if(c instanceof Array)return"array";else if(c instanceof Object)return a;var d=Object.prototype.toString.call(c);if(d=="[object Window]")return"object";if(d=="[object Array]"||typeof c.length=="number"&&typeof c.splice!="undefined"&&typeof c.propertyIsEnumerable!="undefined"&&!c.propertyIsEnumerable("splice"))return"array";if(d=="[object Function]"||typeof c.call!="undefined"&&typeof c.propertyIsEnumerable!="undefined"&&!c.propertyIsEnumerable("call"))return"function"}else return"null";
else if(a=="function"&&typeof c.call=="undefined")return"object";return a}function ba(c){return typeof c=="string"}Math.floor(Math.random()*2147483648).toString(36);var ca={"\000":"\\0","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\x0B",'"':'\\"',"\\":"\\\\"},da={"'":"\\'"};
function ea(c){var m;c=String(c);if(c.quote)return c.quote();else{for(var a=['"'],d=0;d31&&g<127))if(e in da)e=da[e];else if(e in ca)m=da[e]=ca[e],e=m;else{g=e;o=e.charCodeAt(0);if(o>31&&o<127)g=e;else{if(o<256){if(g="\\x",o<16||o>256)g+="0"}else g="\\u",o<4096&&(g+="0");g+=o.toString(16).toUpperCase()}e=da[e]=g}o=e}h[l]=o}a.push('"');return a.join("")}}
function fa(c){for(var a=0,d=0;de;default:return c.apply(this,
arguments)}b("Invalid arity: "+arguments.length)};a.c=2;a.a=function(a){var e=K(a),g=K(M(a)),a=L(M(a));return c.call(f,e,g,a)};return a}();function gb(c){return eb.call(f,c,1)}function hb(c,a){return c^a}function ib(c,a){return c<>a}function kb(c){return O.call(f,0,c)}function lb(c,a){for(var d=a,e=J.call(f,c);;)if(s(function(){var a=e;return s(a)?kb.call(f,d):a}()))var g=gb.call(f,d),h=M.call(f,e),d=g,e=h;else return e}
x._=function(){return function(c,a,d){switch(arguments.length){case 2:var e;var g=lb.call(f,c,a);s(g)?e=K.call(f,g):b("Index out of bounds");return e;case 3:return e=lb.call(f,c,a),s(e)?K.call(f,e):d}b("Invalid arity: "+arguments.length)}}();
var Q=function(){function c(c,e){var g=I(Array.prototype.slice.call(arguments,1),0);return function(c,d){for(;;)if(s(d))var e=c.append(a.call(f,K.call(f,d))),g=M.call(f,d),c=e,d=g;else return a.call(f,c)}.call(f,new r(a.call(f,c)),g)}var a=f,a=function(a,e){switch(arguments.length){case 0:return"";case 1:return s(C.call(f,a))?"":a.toString();default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=1;a.a=function(a){var e=K(a),a=L(a);return c.call(f,e,a)};return a}(),mb=function(){return function(c,
a,d){switch(arguments.length){case 2:return c.substring(a);case 3:return c.substring(a,d)}b("Invalid arity: "+arguments.length)}}();function H(c,a){return Za.call(f,s(Ua.call(f,a))?function(){for(var d=J.call(f,c),e=J.call(f,a);;)if(s(C.call(f,d)))return C.call(f,e);else if(s(C.call(f,e)))return!1;else if(s(B.call(f,K.call(f,d),K.call(f,e))))d=M.call(f,d),e=M.call(f,e);else return s("\ufdd0'else")?!1:f}():f)}
function nb(c,a){return hb.call(f,c,db.call(f,a,2654435769,ib.call(f,c,6),jb.call(f,c,2)))}function R(c){return N.call(f,function(a,c){return nb.call(f,a,Ta.call(f,c))},Ta.call(f,K.call(f,c)),M.call(f,c))}function ob(c,a,d,e){this.b=c;this.C=a;this.z=d;this.count=e}k=ob.prototype;k.f=function(c,a){return H.call(f,c,a)};k.i=function(c,a){return new ob(this.b,a,c,E.call(f,this.count))};k.o=i("C");k.p=i("z");k.h=aa();k.m=!0;k.n=i("b");k.j=function(c){return R.call(f,c)};k.t=i("count");k.q=!0;
function pb(c){this.b=c}k=pb.prototype;k.f=function(c,a){return H.call(f,c,a)};k.i=function(c,a){return new ob(this.b,a,f,1)};k.o=j(f);k.p=j(f);k.h=j(f);k.m=!0;k.n=i("b");k.j=function(c){return R.call(f,c)};k.t=j(0);k.q=!0;var qb=new pb(f);function rb(c){return N.call(f,Oa,qb,c)}function D(c){var a=I(Array.prototype.slice.call(arguments,0),0);return N.call(f,Oa,qb,rb.call(f,a))}function sb(c,a,d){this.b=c;this.C=a;this.z=d}k=sb.prototype;k.h=aa();k.j=function(c){return R.call(f,c)};
k.f=function(c,a){return H.call(f,c,a)};k.q=!0;k.i=function(c,a){return new sb(f,a,c)};k.o=i("C");k.p=function(){return s(C.call(f,this.z))?qb:this.z};k.m=!0;k.n=i("b");function S(c,a){return new sb(f,c,a)}z.string=function(){return function(c,a,d){switch(arguments.length){case 2:return G.call(f,c,a);case 3:return G.call(f,c,a,d)}b("Invalid arity: "+arguments.length)}}();
y.string=function(){return function(c,a,d){switch(arguments.length){case 2:return x.call(f,c,a);case 3:return x.call(f,c,a,d)}b("Invalid arity: "+arguments.length)}}();x.string=function(){return function(c,a,d){switch(arguments.length){case 2:return s(O.call(f,a,w.call(f,c)))?c.charAt(a):f;case 3:return s(O.call(f,a,w.call(f,c)))?c.charAt(a):d}b("Invalid arity: "+arguments.length)}}();w.string=function(c){return c.length};Ca.string=function(c){return Ka.call(f,c,0)};
Aa.string=function(c){return fa.call(f,c)};this.String.prototype.call=function(){return function(c,a,d){switch(arguments.length){case 2:return Qa.call(f,a,this.toString());case 3:return Qa.call(f,a,this.toString(),d)}b("Invalid arity: "+arguments.length)}}();function tb(c){var a=c.x;return s(c.D)?a:(c.x=a.call(f),c.D=!0,c.x)}function T(c,a,d){this.b=c;this.D=a;this.x=d}k=T.prototype;k.h=function(c){return J.call(f,tb.call(f,c))};k.j=function(c){return R.call(f,c)};
k.f=function(c,a){return H.call(f,c,a)};k.q=!0;k.i=function(c,a){return S.call(f,a,c)};k.o=function(c){return K.call(f,tb.call(f,c))};k.p=function(c){return L.call(f,tb.call(f,c))};k.m=!0;k.n=i("b");function U(c){for(var a=v.call(f);;)if(s(J.call(f,c)))a.push(K.call(f,c)),c=M.call(f,c);else return a}function ub(c,a){for(var d=c,e=a,g=0;;)if(s(function(){var a=kb.call(f,e);return s(a)?J.call(f,d):a}()))var h=M.call(f,d),l=gb.call(f,e),g=E.call(f,g),d=h,e=l;else return g}
var wb=function vb(a){return s(C.call(f,a))?f:s(C.call(f,M.call(f,a)))?J.call(f,K.call(f,a)):s("\ufdd0'else")?S.call(f,K.call(f,a),vb.call(f,M.call(f,a))):f},xb=function(){function c(a,c,d){var e=I(Array.prototype.slice.call(arguments,2),0);return function t(a,c){return new T(f,!1,function(){var d=J.call(f,a);return s(d)?S.call(f,K.call(f,d),t.call(f,L.call(f,d),c)):s(c)?t.call(f,K.call(f,c),M.call(f,c)):f})}.call(f,g.call(f,a,c),e)}function a(a,c){return new T(f,!1,function(){var d=J.call(f,a);return s(d)?
S.call(f,K.call(f,d),g.call(f,L.call(f,d),c)):c})}function d(a){return new T(f,!1,function(){return a})}function e(){return new T(f,!1,j(f))}var g=f,g=function(g,l,o){switch(arguments.length){case 0:return e.call(this);case 1:return d.call(this,g);case 2:return a.call(this,g,l);default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};g.c=2;g.a=function(a){var d=K(a),e=K(M(a)),a=L(M(a));return c.call(f,d,e,a)};return g}(),yb=function(){function c(a,c,g,h,l){var o=I(Array.prototype.slice.call(arguments,
4),0);return S.call(f,a,S.call(f,c,S.call(f,g,S.call(f,h,wb.call(f,o)))))}var a=f,a=function(a,e,g,h,l){switch(arguments.length){case 1:return J.call(f,a);case 2:return S.call(f,a,e);case 3:return S.call(f,a,S.call(f,e,g));case 4:return S.call(f,a,S.call(f,e,S.call(f,g,h)));default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=4;a.a=function(a){var e=K(a),g=K(M(a)),h=K(M(M(a))),l=K(M(M(M(a)))),a=L(M(M(M(a))));return c.call(f,e,g,h,l,a)};return a}(),zb=function(){function c(a,
c,g,h,l,o){var m=I(Array.prototype.slice.call(arguments,5),0),m=S.call(f,c,S.call(f,g,S.call(f,h,S.call(f,l,wb.call(f,m))))),p=a.c;return s(a.a)?s(P.call(f,ub.call(f,m,p),p))?a.apply(a,U.call(f,m)):a.a(m):a.apply(a,U.call(f,m))}var a=f,a=function(a,e,g,h,l,o){switch(arguments.length){case 2:var m=a,p=e,t=m.c;return s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,p)):m.a(p):m.apply(m,U.call(f,p));case 3:return m=a,p=yb.call(f,e,g),t=m.c,s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,
p)):m.a(p):m.apply(m,U.call(f,p));case 4:return m=a,p=yb.call(f,e,g,h),t=m.c,s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,p)):m.a(p):m.apply(m,U.call(f,p));case 5:return m=a,p=yb.call(f,e,g,h,l),t=m.c,s(m.a)?s(P.call(f,ub.call(f,p,t),t))?m.apply(m,U.call(f,p)):m.a(p):m.apply(m,U.call(f,p));default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=5;a.a=function(a){var e=K(a),g=K(M(a)),h=K(M(M(a))),l=K(M(M(M(a)))),o=K(M(M(M(M(a))))),a=L(M(M(M(M(a)))));return c.call(f,
e,g,h,l,o,a)};return a}();function Ab(c,a){for(;;)if(s(C.call(f,J.call(f,a))))return!0;else if(s(c.call(f,K.call(f,a))))var d=c,e=M.call(f,a),c=d,a=e;else return s("\ufdd0'else")?!1:f}function Bb(c){return c}
var V=function(){function c(a,c,d,e,p){var t=I(Array.prototype.slice.call(arguments,4),0);return g.call(f,function(c){return zb.call(f,a,c)},function Nb(a){return new T(f,!1,function(){var c=g.call(f,J,a);return s(Ab.call(f,Bb,c))?S.call(f,g.call(f,K,c),Nb.call(f,g.call(f,L,c))):f})}.call(f,Oa.call(f,t,e,d,c)))}function a(a,c,d,e){return new T(f,!1,function(){var p=J.call(f,c),t=J.call(f,d),Ia=J.call(f,e);return s(s(p)?s(t)?Ia:t:p)?S.call(f,a.call(f,K.call(f,p),K.call(f,t),K.call(f,Ia)),g.call(f,
a,L.call(f,p),L.call(f,t),L.call(f,Ia))):f})}function d(a,c,d){return new T(f,!1,function(){var e=J.call(f,c),p=J.call(f,d);return s(s(e)?p:e)?S.call(f,a.call(f,K.call(f,e),K.call(f,p)),g.call(f,a,L.call(f,e),L.call(f,p))):f})}function e(a,c){return new T(f,!1,function(){var d=J.call(f,c);return s(d)?S.call(f,a.call(f,K.call(f,d)),g.call(f,a,L.call(f,d))):f})}var g=f,g=function(g,l,o,m,p){switch(arguments.length){case 2:return e.call(this,g,l);case 3:return d.call(this,g,l,o);case 4:return a.call(this,
g,l,o,m);default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};g.c=4;g.a=function(a){var d=K(a),e=K(M(a)),g=K(M(M(a))),p=K(M(M(M(a)))),a=L(M(M(M(a))));return c.call(f,d,e,g,p,a)};return g}(),Db=function Cb(a,d){return new T(f,!1,function(){if(s(kb.call(f,a))){var e=J.call(f,d);return s(e)?S.call(f,K.call(f,e),Cb.call(f,gb.call(f,a),L.call(f,e))):f}else return f})};
function Eb(c,a){function d(a,c){for(;;){var d=J.call(f,c);if(s(function(){var c=kb.call(f,a);return s(c)?d:c}()))var l=gb.call(f,a),o=L.call(f,d),a=l,c=o;else return d}}return new T(f,!1,function(){return d.call(f,c,a)})}
var Fb=function(){function c(c){return new T(f,!1,function(){return S.call(f,c,a.call(f,c))})}var a=f;return a=function(d,e){switch(arguments.length){case 1:return c.call(this,d);case 2:return Db.call(f,d,a.call(f,e))}b("Invalid arity: "+arguments.length)}}(),Gb=function(){function c(a,c,h){var l=I(Array.prototype.slice.call(arguments,2),0);return new T(f,!1,function(){var h=V.call(f,J,Oa.call(f,l,c,a));return s(Ab.call(f,Bb,h))?xb.call(f,V.call(f,K,h),zb.call(f,d,V.call(f,L,h))):f})}function a(a,
c){return new T(f,!1,function(){var h=J.call(f,a),l=J.call(f,c);return s(s(h)?l:h)?S.call(f,K.call(f,h),S.call(f,K.call(f,l),d.call(f,L.call(f,h),L.call(f,l)))):f})}var d=f,d=function(d,g,h){switch(arguments.length){case 2:return a.call(this,d,g);default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};d.c=2;d.a=function(a){var d=K(a),h=K(M(a)),a=L(M(a));return c.call(f,d,h,a)};return d}();function Hb(c,a){return Eb.call(f,1,Gb.call(f,Fb.call(f,c),a))}
function Ib(c){return function d(c,g){return new T(f,!1,function(){var h=J.call(f,c);return s(h)?S.call(f,K.call(f,h),d.call(f,L.call(f,h),g)):s(J.call(f,g))?d.call(f,K.call(f,g),L.call(f,g)):f})}.call(f,f,c)}
var Jb=function(){function c(a,c,g){var h=I(Array.prototype.slice.call(arguments,2),0);return Ib.call(f,zb.call(f,V,a,c,h))}var a=f,a=function(a,e,g){switch(arguments.length){case 2:return Ib.call(f,V.call(f,a,e));default:return c.apply(this,arguments)}b("Invalid arity: "+arguments.length)};a.c=2;a.a=function(a){var e=K(a),g=K(M(a)),a=L(M(a));return c.call(f,e,g,a)};return a}(),Kb=function(){function c(a,c,h,l){return new T(f,!1,function(){var o=J.call(f,l);if(s(o)){var m=Db.call(f,a,o);return s(B.call(f,
a,Pa.call(f,m)))?S.call(f,m,d.call(f,a,c,h,Eb.call(f,c,o))):D.call(f,Db.call(f,a,xb.call(f,m,h)))}else return f})}function a(a,c,h){return new T(f,!1,function(){var l=J.call(f,h);if(s(l)){var o=Db.call(f,a,l);return s(B.call(f,a,Pa.call(f,o)))?S.call(f,o,d.call(f,a,c,Eb.call(f,c,l))):f}else return f})}var d=f;return d=function(e,g,h,l){switch(arguments.length){case 2:return d.call(f,e,e,g);case 3:return a.call(this,e,g,h);case 4:return c.call(this,e,g,h,l)}b("Invalid arity: "+arguments.length)}}();
function W(c,a){this.b=c;this.d=a}k=W.prototype;k.f=function(c,a){return H.call(f,c,a)};k.i=function(c,a){var d=ia.call(f,this.d);d.push(a);return new W(this.b,d)};k.h=function(){var c=this;return s(fb.call(f,c.d.length,0))?function d(e){return new T(f,!1,function(){return s(O.call(f,e,c.d.length))?S.call(f,c.d[e],d.call(f,E.call(f,e))):f})}.call(f,0):f};k.G=!0;
k.w=function(){function c(a,c,g){var h=this;return s(function(){var a=P.call(f,0,c);return s(a)?O.call(f,c,h.d.length):a}())?h.d[c]:g}function a(a,c){var g=this;return s(function(){var a=P.call(f,0,c);return s(a)?O.call(f,c,g.d.length):a}())?g.d[c]:f}return function(d,e,g){switch(arguments.length){case 2:return a.call(this,0,e);case 3:return c.call(this,0,e,g)}b("Invalid arity: "+arguments.length)}}();k.m=!0;k.n=i("b");
k.v=function(){return function(c,a,d){switch(arguments.length){case 2:return G.call(f,this.d,a);case 3:return G.call(f,this.d,a,d)}b("Invalid arity: "+arguments.length)}}();k.j=function(c){return R.call(f,c)};k.t=function(){return this.d.length};k.q=!0;k.B=function(c,a,d){c=ia.call(f,this.d);c[a]=d;return new W(this.b,c)};k.u=function(){return function(c,a,d){switch(arguments.length){case 2:return x.call(f,c,a,f);case 3:return x.call(f,c,a,d)}b("Invalid arity: "+arguments.length)}}();
var Lb=new W(f,v.call(f));function Mb(c){return new W(f,c)}W.prototype.call=function(){return function(c,a,d){switch(arguments.length){case 2:return y.call(f,this,a);case 3:return y.call(f,this,a,d)}b("Invalid arity: "+arguments.length)}}();function Ob(c){return N.call(f,Oa,Lb,c)}function Pb(){}Pb.prototype.f=j(!1);var Qb=new Pb;
function Rb(c,a){return Za.call(f,s(Va.call(f,a))?s(B.call(f,Pa.call(f,c),Pa.call(f,a)))?Ab.call(f,Bb,V.call(f,function(c){return B.call(f,Qa.call(f,a,K.call(f,c),Qb),La.call(f,c))},c)):f:f)}function Sb(c,a,d){for(var e=d.length,g=0;;)if(s(O.call(f,g,e)))if(s(B.call(f,a,d[g])))return g;else g=db.call(f,g,c);else return f}v.call(f);function X(c,a,d){this.b=c;this.count=a;this.r=d}k=X.prototype;k.f=function(c,a){return Rb.call(f,c,a)};
k.i=function(c,a){return s(Wa.call(f,a))?ra.call(f,c,x.call(f,a,0),x.call(f,a,1)):N.call(f,la,c,a)};k.h=function(){var c=this;if(s(kb.call(f,c.count))){var a=Xa.call(f,c.r);return Jb.call(f,function(a){return V.call(f,Ob,Kb.call(f,2,c.r[a]))},a)}else return f};k.F=!0;k.m=!0;k.n=i("b");k.j=function(c){return R.call(f,c)};k.t=i("count");
k.B=function(c,a,d){var c=Ta.call(f,a),e=this.r[c];if(s(e)){var e=ia.call(f,e),g=ha.call(f,this.r);g[c]=e;c=Sb.call(f,2,a,e);return s(c)?(e[E.call(f,c)]=d,new X(this.b,this.count,g)):(e.push(a,d),new X(this.b,E.call(f,this.count),g))}else return e=ha.call(f,this.r),e[c]=v.call(f,a,d),new X(this.b,E.call(f,this.count),e)};
k.u=function(){return function(c,a,d){switch(arguments.length){case 2:return y.call(f,c,a,f);case 3:var e=this.r[Ta.call(f,a)],g=s(e)?Sb.call(f,2,a,e):f;return s(g)?e[E.call(f,g)]:d}b("Invalid arity: "+arguments.length)}}();var Tb=new X(f,0,function(){return{}}.call(f));X.prototype.call=function(){return function(c,a,d){switch(arguments.length){case 2:return y.call(f,this,a);case 3:return y.call(f,this,a,d)}b("Invalid arity: "+arguments.length)}}();
function Ha(c){for(var a=I(Array.prototype.slice.call(arguments,0),0),a=J.call(f,a),d=Tb;;)if(s(a))var e=Ma.call(f,a),d=Ra.call(f,d,K.call(f,a),La.call(f,a)),a=e;else return d}Ha.call(f);function Ub(c){if(s($a.call(f,c)))return c;else if(s(function(){var a=ab.call(f,c);return s(a)?a:bb.call(f,c)}())){var a=c.lastIndexOf("/");return s(O.call(f,a,0))?mb.call(f,c,2):mb.call(f,c,E.call(f,a))}else return f}
function Vb(c){if(s(function(){var a=ab.call(f,c);return s(a)?a:bb.call(f,c)}())){var a=c.lastIndexOf("/");return s(fb.call(f,a,-1))?mb.call(f,c,2,a):f}else return"\ufdd0'else"}function Y(c,a,d,e,g,h){return xb.call(f,Mb([a]),Ib.call(f,Hb.call(f,Mb([d]),V.call(f,function(a){return c.call(f,a,g)},h))),Mb([e]))}
var Z=function Wb(a,d){return s(C.call(f,a))?D.call(f,"nil"):s(Ya.call(f,a))?D.call(f,"#"):s("\ufdd0'else")?xb.call(f,s(function(){var e=Qa.call(f,d,"\ufdd0'meta");return s(e)?(e=s(s(a)?a.m:a)?!0:u.call(f,ua,a),s(e)?Sa.call(f,a):e):e}())?xb.call(f,Mb(["^"]),Wb.call(f,Sa.call(f,a),d),Mb([" "])):f,s(s(s(a)?a.k:a)?!0:u.call(f,A,a))?Fa.call(f,a,d):D.call(f,"#<",Q.call(f,a),">")):f};X.prototype.k=!0;
X.prototype.g=function(c,a){return Y.call(f,function(c){return Y.call(f,Z,""," ","",a,c)},"{",", ","}",a,c)};A.number=!0;Fa.number=function(c){return D.call(f,Q.call(f,c))};Ja.prototype.k=!0;Ja.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};T.prototype.k=!0;T.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};A["boolean"]=!0;Fa["boolean"]=function(c){return D.call(f,Q.call(f,c))};A.string=!0;
Fa.string=function(c,a){return s(ab.call(f,c))?D.call(f,Q.call(f,":",function(){var a=Vb.call(f,c);return s(a)?Q.call(f,a,"/"):f}(),Ub.call(f,c))):s(bb.call(f,c))?D.call(f,Q.call(f,function(){var a=Vb.call(f,c);return s(a)?Q.call(f,a,"/"):f}(),Ub.call(f,c))):s("\ufdd0'else")?D.call(f,s("\ufdd0'readably".call(f,a))?ea.call(f,c):c):f};W.prototype.k=!0;W.prototype.g=function(c,a){return Y.call(f,Z,"["," ","]",a,c)};ob.prototype.k=!0;ob.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};
A.array=!0;Fa.array=function(c,a){return Y.call(f,Z,"#",a,c)};pb.prototype.k=!0;pb.prototype.g=function(){return D.call(f,"()")};sb.prototype.k=!0;sb.prototype.g=function(c,a){return Y.call(f,Z,"("," ",")",a,c)};function Xb(c){return Q.call(f,"Hello ",c)}var Yb="hello.greet".split("."),$=this;!(Yb[0]in $)&&$.execScript&&$.execScript("var "+Yb[0]);for(var Zb;Yb.length&&(Zb=Yb.shift());)!Yb.length&&Xb!==void 0?$[Zb]=Xb:$=$[Zb]?$[Zb]:$[Zb]={};

Webでの実行

<html>
  <head></head>
  <body>
    <script type="text/javascript" src="hello.js"></script>
    <script>
      alert(hello.greet("ClojureScript"))
    </script>
  </body>
</html>

感想

お、動くじゃん。

ただ、CoffeeScriptの利点は吐かれるJSもかなり可読性が高いものになる(それこそ俺が適当に手書きしたJSより)というところだと思うので、元々関数型で結構書きやすいJSを関数型言語からイミフなJSにコンパイルするのはちょっとなーという感じです。モジュール性を高めたい場合にはunderscore.js等を使ってJSネイティブで関数型っぽく書く方が僕は惹かれています。

ClojureScriptをnodejsで動かすって部分は更にイミフです。サーバーサイドだったらClojureそのもので書いたらえんちゃうの?

JavascriptはWebのアセンブラだ!っていう考えは今後主流になったりするんでしょうかね。どうなんでしょうかね。

こういうの書きたい。

// unk.js
$('#unk').click(function(){
  alert('unk')
})

けどcoffeeでは、

# unk.coffee
$('#unk').click ->
  alert 'unk'
,

キモイー。何かあるのかな?

最近のpowはコンフリクトしない。完。

あなたの Web サイト

powはversion毎のディレクトリを作ってlatestなものにcurrentからsymlinkが張られるのでupdateも普通にインストールするだけでいい。

$ curl get.pow.cx | sh
// fib.js
function fib(n) {
  if (n == 0 || n == 1) return n;
  return fib(n - 1) + fib(n - 2);
}
$ npm install js2coffee -g
$ js2coffee fib.js > fib.coffee
// fib.coffee
fib = (n) ->
  if n == 0 or n == 1
    return n
  fib(n - 1) + fib(n - 2)

「(既存プロジェクトのjsを変換して)ふー・・・」

「弊社もcoffee導入しました(キリッ」

  • nave = rvm
  • node.js = ruby(ex:mri-ruby)
  • npm = rubygems

nave

$ git clone git://github.com/isaacs/nave.git ~/.nave
$ cd ~/.nave
$ ./nave.sh install stable

ここで普通は~/.zshrcとかにnave.sh use stableとか書けとありますが、設定したshellをもう一段階開くのが何か嫌だ。(確かにVirtual Environment for Nodeって感じではあるが)

Terminal — zsh — 80×24

キモス。

% env | grep NODE
NODE_PATH=/Users/komagata/.nave/installed/0.4.8/lib/node
% env | grep NAVE
NAVEVERSION=0.4.8
NAVE=0.4.8
NAVELVL=1
NAVE_DIR=/Users/komagata/.nave
NAVE_ROOT=/Users/komagata/.nave/installed
NAVE_SRC=/Users/komagata/.nave/src

それっぽい環境変数+PATHを手動で.zshrc設定に手動で設定することにした。

export PATH=~/.nave/installed/0.4.8/bin:$PATH
export NODE_PATH=/Users/komagata/.nave/installed/0.4.8/lib/node
export NAVEVERSION=0.4.8
export NAVE=0.4.8
export NAVELVL=1
export NAVE_DIR=/Users/komagata/.nave
export NAVE_ROOT=/Users/komagata/.nave/installed
export NAVE_SRC=/Users/komagata/.nave/src

npm

$ curl http://npmjs.org/install.sh | sh

インストールは楽。

1.0.0から?は普通にnpm installするとcurrent directoryのnode_module以下に入る。この名前も嫌だなあ。そうするとライブラリはプロジェクト毎のnode_moduleに入り、普段使いのコマンドとして使えない。その場合は-g(global)オプションを付けてinstallすればいいらしい。

$ npm install coffee-script -g

これでcoffeeコマンドが使えるようになりました。

しかし、これだとrequire出来なくなっちゃうのでnpm link fooでglobalな場所に入ったライブラリからcurrentのnode_moduleへシンボリックリンクを貼る必要がある。これはsucksでございます。

動きの早い界隈なので暫くしたらもっと便利になるかもしれません。

vim-coffee-script

Bundle 'kchmck/vim-coffee-script'

vundlerを使ってる場合は上記を.vimrcに追加して:BundleInstall。また、autocmdでファイル保存と同時にcompileするようにしてもいいけど、railsとかだとディレクトリ違うのでウザイかも。

:CoffeeMakeでコンパイル。

Terminal — vim — 80×24

:'<,'>CoffeeCompile
console.log('foo');

visual選択してcompileなんてシャレオツなことも。

cofeescriptを使ってみました。気になっていたのは親クラスのコンストラクタを呼ぶ方法(のスマートな書き方)。

以前は、JavaScript Good Partsに載っていたnewやprototypeを使わない方法でやっていたんですが、coffeeのextendsはどういうコードを吐くんだろう?

// foo.coffee
class Foo
  constructor: (name) ->       
    console.log name           

class Bar extends Foo          
  constructor: ->
    super 'unk'
// foo.js
var Bar, Foo;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { 
  for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 
  function ctor() { this.constructor = child; } 
  ctor.prototype = parent.prototype;
  child.prototype = new ctor;
  child.__super__ = parent.prototype;
  return child;
};
Foo = (function() { 
  function Foo(name) { 
    console.log(name);
  } 
  return Foo;
})();
Bar = (function() { 
  __extends(Bar, Foo);
  function Bar() { 
    Bar.__super__.constructor.call(this, 'unk');
  } 
  return Bar;
})();

オブジェクト指向で書けるライブラリによくあるextends関数を作ってそれを使ってるだけでした。まあ、そりゃそうか。

coffee自体は綺麗だし、SASS/SCSSみたいに最初のうちは吐かれたjsを確認しながらになるけど、段々js見る頻度が減ってきてるので殆ど見ないで行けるようになれば使えるなーと思いました。

JPNewTechのイベントに行ってビックリした - komagata [p0t]

こんな事書きましたが、そういえば今まで誰にも共感されたことないし、当時かなり衝撃を受けて熱中してたので自分の中では自明のこと過ぎて説明が足りなすぎるかなと思ったのでもう少し詳しく書いてみます。

まず、「XHRでもWebDAV使えるっぽい」っていうエントリーがあって、その時点で、「うお、マジかよ。その発想は無かったわ」って感じです。で、「ってことはもしかして・・・?」ってうっすら。

XMLHttpRequestでWebDAV - snippets from shinichitomita’s journal

で、WebDAVサービス上で動く、HTML+JavaScriptだけで作られたブログエンジンというエントリーでwebdablogという形で僕の様な貧弱一般人(@ブロントさん)にも露骨に分かるソフトウェアの形で公開されました。そのソースコードを読んでビックリしました。

2006年の時点でもWebDAVなんて一昔前の技術で、その存在とかは誰でも知ってたわけでそれを使ってクライアントサイド実装のみでJSONで保存して表示もやるというのが面白かったし、裏技的に見えてHTTPの本質をついてると思いました。

webdav.jsのコードの字面を見ても「そんなに興奮するものか?」って思うかもしれないけど、webdav.jsは単独で公開されたものじゃなくて、上記のwebdablogの中に数あるソースコードのうちの1ファイル。僕が勝手にwebdav.jsだけ取り上げて騒いでるだけなんですが、webdablogのコンセプトも面白かったし、そのコンセプトをwebdav.jsという形に切り出しているのがとてもスマートだと思いました。

どう実装するか?ということより、何を実装するのか?という問題設定とプログラムの粒度の設定がとてつもなくスゴイと思ったのです。

そして、どう実装するか?の部分も力技でゴリゴリと書いてあったら興醒めだけど、全く力の抜けたシンプルでスマートな書き方がしてある。こういうのこそ僕が目指したいコードだと思った訳です。だから一般的に"凄いコード"と聞いて連想する感じとはちょっと違うかもしれません。

「わざわざそんな事言わんでも@stomitaがスゴイことなんてわかっとるわ」

という方もおられるとは思いますが、5年前にそんなことがあったよというお話でした。