読者です 読者をやめる 読者になる 読者になる

素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: すかいぷ:javascripter_  か javascripter あっと tsukkun.net skypeのほうがいいです

RubyでJavaScriptのプロトタイプもどき

prototype - 素人がプログラミングを勉強するブログの続き。RubyユーザがJavaScriptオブジェクト指向を学ぶ時に使えるかもしれない。

=begin
JavaScriptのようなオブジェクトの実装。
JSObject.newがJavaScriptのnew Object()相当であり、プロパティへの代入で値をセットする。
=end
class JSObject < Object # Ruby1.9ならBasicObjectを継承すべき
    def initialize
        @object = {}
    end

=begin
JavaScriptのobject["key"]構文の実装。
objectのハッシュテーブルからキーで探し、無かったら"__proto__"プロパティから探し…と再帰的に動く。
"__proto__"がnilだったらnilを返す。
実体はprivate関数のref
=end
    def [](name)
        ref(@object, name)
    end

=begin
値の代入は__proto__とは関係がない
=end
    def []=(name, value)
        @object[name] = value
    end

=begin
JavaScriptの.演算子相当の実装。ほとんどの処理を[]と[]=へ移譲。
=end
    def method_missing(name, value=nil)
        if name.to_s =~ /=$/
            self[name.to_s[0..-2]] = value
        else
            self[name.to_s]
        end
    end

    private
    def ref(obj, name)
        if obj.has_key?(name)
            obj[name]
        elsif obj["__proto__"].nil?
            nil
        else
            ref(obj["__proto__"], name)
        end
    end
end

=begin
JavaScriptのようなコンストラクタの実装。
JSConstructorを継承しinitメソッドをオーバーライドして使う。
class F < JSConstructor
    def init;end
    def foo;end
end
F.new
JavaScriptでの
function F(){}
F.prototype.foo = function(){};
new F();
に相当する。
=end
class JSConstructor
    attr_reader :this
    def initialize(*args)
        @this = JSObject.new
        @this.__proto__ = this.prototype
        init(*args) || @this
    end

    def init;end
end

=begin
実例。
JavaScriptでの、
function Position(x, y) {
    this.x = x;
    this.y = y;
}
Position.prototype.get_x = function () {return this.x;};
Position.prototype.get_y = function() {return this.y;};
Position.prototype.get_size = function () {return this.x * this.y;};

var pos = new Position(10, 20);
document.writeln(pos.get_x());
document.writeln(pos.get_y());
document.writeln(pos.get_size());
に相当する。
=end
class Position < JSConstructor
    def init(x, y)
        this.x = x
        this.y = y
    end

    def get_x
        this.x
    end

    def get_y
        this.y
    end

    def get_size
        this.x * this.y
    end
end

pos = Position.new(10, 20)
puts pos.get_x # 10
puts pos.get_y # 20
puts pos.get_size # 30