JavaScriptでJava風にsuperクラスにアクセスするライブラリ作った

https://github.com/ukyo/jssuper

※ProxyとECMA5が実装されている処理系で動かしてね。
追記:prototypeチェーンにsuperが2つ絡むとループすることに気がついた・・・のだけど、解決法がわからん。superは一回だけでお願いします(これはひどい)。

まぁ、ソースコードはこれだけなんですが。しかしながら、プロパティだとsuperって書いても一応平気なんですね・・・。
Object.defineProperty(Object.prototype, 'super', {
get: function() {
var superProto, method, constructor;

superProto = Object.getPrototypeOf(Object.getPrototypeOf(this));

method = function(rcvr, name) {
return superProto[name].bind(this);
}.bind(this);

constructor = function() {
superProto.constructor.apply(this, arguments);
}.bind(this);

return Proxy.createFunction({get: method}, constructor);
}
});

こんな感じで使えます。extendする系のライブラリでも普通に動くと思います。
function A(message) {
this.message = message;
}

function B() {
//super classのコンストラクタを呼ぶ
this.super('hello!');
}
B.prototype = Object.create(A.prototype);

A.prototype.foo = function() {
return '#' + this.message + '#';
};

B.prototype.foo = function() {
//super classのメソッドを呼ぶ
//もちろんcall(this)しなくてもOK
return '(' + this.super.foo() + ')';
};

var b = new B;
b.foo(); // '(#hello!#);'が返ってくる。
posted by 右京 | javascript

JavaScriptでPythonのsuperっぽいことをする。

ECMA HarmonyのProxyとECMA5のFunction.prototype.bindを使うと実現できます(たったの7行!)。

superを実現している部分(superは予約語・・・)
var __super = function(self) {
return Proxy.create({
get: function(rcvr, name) {
return self.__proto__.__proto__[name].bind(self);
}
});
};


追記:こうしないとだめだった・・・。単一継承なのに。
var sup = function(self, Class) {
return Proxy.create(
{get: function(rcvr, name) {
name = name === '__init__' ? 'constructor' : name;
return Object.getPrototypeOf(Class.prototype)[name].bind(self);
}}
);
};

posted by 右京 | javascript

extendとmixin

なるべく薄く作ろうとするとこんな感じになるのかなぁ。coffeescriptだと__super__をつくってオーバーライドした親クラスのメソッドを呼んだりして。生のJSで実際にやるとしたら、Hoge.__super__.hoge.call(this, arg1, arg2);みたいにしなければいけないところをsuperと書くだけで同じことができるというのはやっぱりよくできてる(パフォーマンスは別にして)。ただ、proxyが黒魔術的な力を持っているのでオーバーライドしたメソッドから親クラスのメソッドを呼ぶ簡単な方法が提案されたらいいねー。

//extend
//一回ダミーのコンストラクタを作ることによってインスタンス作成時にエラーを出すかんじのものも継承できる
function extend(child, parent) {
var F = function(){};
F.prototype = parent.prototype;
child.prototype = new F;
}

//mixin
function mixin(to, from) {
var tp = to.prototype, k;
for(k in from) if(from.hasOwnProperty(k)) tp[k] = from[k];
}

//usage
function A(name){
if(typeof name !== 'string') throw new TypeError('name must be string.');
this.name = name;
}

A.prototype.hello = function() {
alert(this.name + ' says hello.');
};

var MeifukusigatakiMixin = {
woonyaa: function(){
alert('(」・ω・)」うー!(/・ω・)/にゃー!と叫ぶ' + this.name);
}
};

function B(name){
A.call(this, name);
}
//extendしてからmixinしないとダメ!
extend(B, A);
mixin(B, MeifukusigatakiMixin);

var b = new B('ハスターくん');
b.hello();
b.woonyaa();

function C(name){
B.call(this, name);
}
extend(C, B);

var UnkoMixin = {
unko: function() {
alert('うんこをする' + this.name);
}
};

mixin(B, UnkoMixin);
b.unko();

var c = new C('ニャル子');
c.hello();
c.woonyaa();
c.unko(); //prototypeチェーンに入っているのでもちろんOK
posted by 右京 | javascript

愉快なforEach

Array.prototypeには結構愉快なメソッドがあって、そのメソッドを他のオブジェクトのprototypeにくっつけても動くようなのもある。走査系というんですかね、lengthがあって0,1,2...みたいにシーケンシャルにアクセスするようなやつ。例えばforEach(もちろん他にもあるんだけど)。

function addEach() {
var each = [].forEach;
arguments.forEach = each;
arguments.forEach(function(obj) {
obj.prototype.forEach = each;
});
}

addEach(String, NodeList, FileList);

上の例でもわかるようにもちろんインスタンスに直接forEachをくっつけることもできる。prototypeチェーンで速度が落ちるのが嫌だとか、prototypeを汚したくない場合はそれもありかもね(call使えばいいのだけど)。
posted by 右京 | javascript

××が出している○○なジャンルのソフトを所持していたという情報

Amazonがゲーム買取の仲介を始めたようで。これ自体ではあまり儲けは出なさそうだが、ユーザの購入データがわかるのはでかい。閲覧データと比べたら格が違う。実際買ってるわけだから、そりゃ相当に興味があるわけだし。使ったらレコメンドの精度が上がるんだろうな。CDとか本とかもやるのかな。もしやったとしても仲介だからAmazonには在庫がいかないんでしょ。頭いいなぁ。
posted by 右京 | 雑記

javascriptのnative APIで任意の文字コードからutf8に変換

1.BlobBuilder#appendで文字列を追加すると自動的にutf8に変換される
2.FileReader#readAsTextで任意の文字コードのBlobを読み込んで文字列に変換できる

これらを使うとなんでもutf8に変換できるね!という話。ただし、任意の文字コード→任意の文字コードはやっぱり変換テーブルが必要だけど。BlobBuilder#appendで文字コード指定できないのかな?

処理の流れ。
Array or Uint8Array or ArrayBuffer -> unicode string -> utf8 ArrayBuffer

posted by 右京 | javascript

巨大な配列から文字列へ変換する場合はnativeで変換すると圧倒的に速い

つまりこういうことです。
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder || window.BlobBuilder),
fr = new FileReader;
bb.append(bytes.buffer);
fr.onloadend = function() {
//何か処理
};
fr.readAsBinaryString(bb.getBlob());

これは一例ですが、ArrayからArrayBuffer作るのも、部分的なArrayBufferを作るのもネイティブでできるので大体のケースでつかえるんじゃないですかね?

for文とネイティブの比較:
http://jsperf.com/bytes-to-string-test
posted by 右京 | javascript

emscriptenでzpipeを変換する過程をcodestre.amで撮ってみた

ちょっとvim操作が不自由なんだけど、撮ってみたよ。linuxの人は割と簡単にできるので試してみるといいかもね。

http://codestre.am/22d71745d4dbb5d7a3dc6018e
posted by 右京 | javascript