ソフトウェアエンジニアの日常の雑記

日々思ったことをまとめます

Javascript:プロトタイプ

Javascriptは普通のオブジェクト指向言語じゃなくて、プロトタイプベースのオブジェクト指向言語のようだ。

            var Person = function(name,age){
                this.name = name;
                this.age = age;
                this.show = function(){
                    return this.name + '(' + this.age + ')';
                };
            };
            var p = new Person('taro',30);
            document.writeln( p + '<br>');
            document.writeln('name:' + p.name + ' age:' + p.age);

実行結果

[object Object]
name:taro age:30

定義されている関数をインスタンス化するのはnewを仕様すればいい。関数をnewしてインスタンス化したものを変数"p"に入れて、表示しようとすると"[object Object]"となる。そして値も取り出せるようになる。ここらへんは、Java等の言語のクラスと同じ考え方でいいと思う。

            var Person = function(name,age){
                this.name = name;
                this.age = age;
                this.show = function(){
                    return this.name + '(' + this.age + ')';
                };
            };
            var p = new Person('taro',30);
            var q = new Person('jiro',29);
            document.writeln(q.show() + '<br>');
            q.rename = function(name){   //  <-- rename関数を追加
                this.name = name;
            }
            q.rename('sabro');
            document.writeln(q.show() + '<br>');
            // p.rename('sabro');  // 存在しない関数の為not definedとなる
            delete q.rename;       // 追加した関数を削除
            // q.rename('shiro');  // 関数は削除されたのでnot definedとなる

変数"q"にだけ関数"rename"を追加する。この時、変数"p"は関数"rename"を追加されていないので呼びだそうとするエラーになる。このようにJavascriptインスタンスにメソッドを追加したり削除したりできる。削除は、関数"delete"を使えばできる。

  • 関数にprototype経由で関数を追加する
            var Person = function(name,age){
                this.name = name;
                this.age = age;
                this.show = function(){
                    return this.name + '(' + this.age + ')';
                };
            };
            var p = new Person('taro',30);
            var q = new Person('jiro',29);
            document.writeln(q.show() + '<br>');
            Person.prototype.rename = function(name){  // prototype経由でメソッドを追加
                this.name = name;
            }
            q.rename('sabro');
            document.writeln(q.show() + '<br>');
            p.rename('shiro');
            document.writeln(p.show() + '<br>');

関数名.prototype.xxx で関数に対して関数を追加できるようになる。これは、関数を追加されるまえにインスタンス化されたものにもすべて適用される。

  • 関数にprototype経由で複数の関数を同時に追加する
            var Person = function(name,age){
                this.name = name;
                this.age = age;
                this.show = function(){
                    return this.name + '(' + this.age + ')';
                };
            };
            // var p = new Person('taro',30);  ここだと追加された関数呼び出しの時にエラーとなる
            Person.prototype = {  // prototype経由でメソッドを追加
                rename : function(name){
                this.name = name;
                },
                birth : function(birth){
                this.birth = birth;
                }
            }
            var p = new Person('taro',30);
            p.rename('sabro');
            document.writeln(p.show() + '<br>');

prototypeにオブジェクトリテラルを渡すことで、関数等をまとめて追加できる。ただし、追加する宣言の前にインスタンス化されたものに関しては関数呼び出しの時にエラーになる。

  • プロトタイプチェーン
            var Person = function(name,age){
                this.walk = function(){
                    return 'walking';
                }
            };
            var WorkingPerson = function(){};
            WorkingPerson.prototype = new Person();
            WorkingPerson.prototype.work = function(){
                 return 'working';
            };
            var workp = new WorkingPerson();
            document.writeln(workp.walk());
            document.writeln(workp.work());

JavascriptJavaの継承みたいなのを実現する為には、プロトタイプチェーンを利用する。関数"WorkingPerson"に関数"Person"を追加するには、prototype経由で関数"WorkingPerson"に関数"Person"のインスタンスを追加する。ただし、関数"Person"をインスタンス化した時点で、関数WorkingPersonのprototypeの中身は書き換わってしまうので注意。