プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

JavaScriptでオブジェクト指向プログラム〜関数電卓を実装してみる〜

Webをやっている人なら一度くらいはJavaScriptに触ったことがあるのではないだろうか?私もJavaScriptを知ってからかれこれ3,4年ぐらいはたった。

そんな身近なスクリプト言語のJavaScriptだが、ひょんな事から実は「オブジェクト指向プログラム」がつくれるのだ、ということを知ったもので、身近だったけど実はよく知らないJavaScriptをちょっと再評価してみることにした。


まず、だいたい、JavaScriptにオブジェクトの概念その物があるのか疑問だったので、4年前に買ったJavaScriptポケットリファレンスを久々に開いてみると、しっかり3章目に「オブジェクト」という項目でデカデカとあった。(;´Д`)
いや〜。もうすっかり本はぼろぼろになってるけど知らなかったわ〜wwwww

オブジェクトを生成するのは簡単で new Object; を実行するだけ。
試しに下のスクリプトを打って実行してみると
var noda= new Object;
noda.x = 5;
noda.y = 8;
document.writeln(noda.x+" "+noda.y);

結果はちゃんと5 8になった。
え?noda.xとnoda.yという変数を用意したのとどう違うのか?

いやいや、変数名に「.」は使えませんから。

つまり、nodaオブジェクトの中にあるx,yにそれぞれ5,8を代入して取得することに成功したわけだ。


しかも、リファレンスをよくよく呼んでみると function の項目は「関数オブジェクト」とデカデカと書かれてある。

つーことは、JavaScriptにおいて関数自体がオブジェクトとして定義できると言うことだ。

だからどうしたって?
これが大事なことなんです。

関数自体がオブジェクトとして定義できることで、JAVAで言うコンストラクタとメソッドの実装が可能になるわけです。
次のような関数を用意しましょう。
function Struct(h,w){
this.height = h;
this.weight = w;
}
thisの意味については長くなりそうなのであまり深く言及しません。
関数がどのheightを今参照しているのか分からなくなるからthisを付けると思えばいいでしょう。
この関数の呼び出しは
var noda = new Struct(183,73);

これでnodaを作った時点でheightとweightが設定されました。とどのつまりこれはコンストラクタに当たりますね。今度はメソッドを実装しましょう。

function Struct(h,w){
this.height = h;
this.weight = w;
this.diet = Struct_DIET;
}
function Struct_DIET(w){
this.weight += w;
}

これで、メソッドが実装できました。このStruct_DIET関数は目標減量体重分体重を増やしてくれますw

これを実行するには noda.diet(5)で実行できます。わざわざStruct_DIETを書かなくてもStruct_DIETが実行できます。

さらにStruct_DIET内にはweightなんて用意していないのに、this.weightとなっています。こうすることで呼び出し元のStruct内weightを別な関数から弄ることが出来ます。なかなか、不思議ですね。



と、いうわけで、フィールドとコンストラクタとメソッドの実装に成功したと言うことはJavaScriptはなんと、オブジェクト指向プログラムだった、ということになりますね〜。いや〜。正直驚きです。


これで、リストとかも実装できますよ〜。

せっかく知ったので何か作ろうと思い立ち、考えてみたところ、ちょうど今日のプログラム講義の演習で、来週までの課題としてでたはいいものの講義中に完成させて提出してしまった「逆ポーランド」の計算プログラムを作るのがよさげ。

でも、同じ内容をやってもつまらないので、普通の(3+5)*7+4/2などの式を計算することにします。眠いので続きにソースだけ載せて明日へ。



実行結果
(8*(12%5)-5)*9+5.4*(12/4) =>8 12 5 % * 5 - 9 * 5.4 12 4 / * + = 115.2

var k = "(8*(12%5)-5)*9+5.4*(12/4)";


var oper = /[0-9]/;
var calc = /[\*/%]/;
var calc2 = /[\+\-]/;


function Struct(d,w,P){
    this.data = d;
    this.weight = w;
    this.next = P;
    this.push = Push;
    this.pop = Pop;
}

function Struct2(W,P,P2){
    this.data = W;
    this.old = P;
    this.new = P2;
    this.push = Push2;
    this.pop = Pop2;
    this.shift = Shift;
    this.unshift = unShift;
}


function Push(d,w){
    var s = new Struct(d,w,this);
    s.next = this;
    return s;
}

function Push2(w){
    var s = new Struct2(w,this,-1);
    this.new = s;
    return s;
}

function Pop(){
    if(this.next == -1){
        return ["false",this]
    }
    var res = [this.data,this.next];
    return res;
}

function Pop2(){
    var k = this.old;
    k.new = -1;
    return [this.data,this.old];
}


function unShift(w){
    var k = new Struct2(w,-1,this);
    this.old = k;
    return k;
}

function Shift(){
    var k = this.new;
    k.old = -1;
    return [this.data,this.new];
}





var p = new Struct(0,0,-1);
var s = new Struct2(0,-1,-1);

var a,b,i,k,n,nflag;

document.write(k+" =>");
n =0;
for(i =0;i < k.length;i++){

    if((k.charAt(i)).match(oper) != null)
    {
        a = k.charAt(i)*1;
        i++;
        n = 10;
        nflag = 0;
        while( (k.charAt(i)).match(oper) != null || (k.charAt(i)).match(/\./) != null)
        {
            if((k.charAt(i)).match(/\./) != null){
                n = 10;
                i++;
                nflag = 1;
                continue;
            }
            if(nflag==1){
                a = a + k.charAt(i)/n;
            }else{
                a = n*a + k.charAt(i)*1;
            }
            n = n*10;
            i++;       
        }
        p = p.push(a,0);
        i = i-1;
    }
    else if((k.charAt(i)).match(calc) != null)
    {

        while(p.next != -1){
            if(p.weight <= 1){
                [a,p] = p.pop();
                s = s.push(a);
            }else{
                break;
            }
        }
        p = p.push(k.charAt(i),1);

    }
    else if((k.charAt(i)).match(calc2) != null)
    {
        while(p.next != -1){
            if(p.weight <= 2){
                [a,p] = p.pop();
                s = s.push(a);
            }else{
                break;
            }
        }
        p = p.push(k.charAt(i),2);

    }else if((k.charAt(i)).match(/\(/) != null){
        p = p.push("(",3);
    }else if((k.charAt(i)).match(/\)/) != null){
        while(p.data != "(" ){
            [a,p] = p.pop();
            s = s.push(a);
        }
        [a,p] = p.pop();
    }
}

while(p.next != -1){
    [a,p] = p.pop();
    s = s.push(a);
}
s = s.push("END");

while(s.old != -1){
s = s.old;
}
[n,s] = s.shift();
while(s.new != -1){
    [n,s] = s.shift();
    document.writeln(n+" ");
    if(typeof(n) == "number")
    {
        p = p.push(n,0);
        continue;
    }
    [b,p] = p.pop();
    [a,p] = p.pop();
    if((n).match(calc) != null)
    {
        if((n).match(/\*/) != null){
            a *= b;
        }else if((n).match(/\//) != null){
            a /= b;
        }else if((n).match(/%/) != null){       
            a %= b;
        }
    }
    else if((n).match(calc2) != null)
    {
        if((n).match(/\+/) != null){
            a += b;
        }else if((n).match(/\-/) != null){
            a -= b;
        }
    }
p = p.push(a,0);
}

document.writeln("= "+p.data);