JavaScriptのprototypeについて

[新着] Webテンプレートを仮オープンしました



0   名前: よし : 2007/05/31(木) 01:21  ID:ihmXNzLK sub-t1
配列ataiにメソッドgetmojiを追加したcataiを作成しました。
ところが、浅学な私の予想に反して、元のataiにもgetmojiが
追加されてしまいます。なぜなのでしょうか。
prototypeに関する理解不足だと思うのですがよくわかりません。
宜しくお願いします。

function myfunc(obj){
function Func(){}
Func.prototype=obj;
Func.prototype.getmoji=function(){return("Hello");};
return(new Func());
}
var atai=[1,2];
var catai=myfunc(atai);
alert(atai.getmoji());//なぜ、Hello?

1   名前: 匿名 : 2007/05/31(木) 01:21  ID:uLGx6Ue6 sub-Cz
(スコープを無視すれば)こう書いているのと同じだから。
var atai = new Array (1, 2);

function Func () { ; }
Func.prototype = atai;
Func.prototype.getMoji = function () { return 'Hello'; };  // == atai.getMoji

atai.getMoji ();           // 'Hello'
// Func.prototype(== atai)の全プロパティが Func インスタンス間で共有される
var catai = new Func;
catai[0];                  // 1
catai[1];                  // 2
catai.length;              // 2
catai.getMoji ();          // 'Hello'

var catai2 = new Func;
catai2[0];                 // 1
catai2[1];                 // 2
catai2.slice (0);          // 1, 2
catai2.getMoji ();         // 'Hello'


// プロトタイプの変更は全インスタンスに影響を及ぼす
atai[0] = 10;
catai[0];                  // 10
catai2[0];                 // 10


// インスタンス側からプロトタイプを(直接的に)変更することはない
catai[0] = 20;             // catai[0] という新しいインスタンスプロパティを作る(オーバーライド)
atai[0];                   // 10
catai[2];                  // 10


// '0' という名前の、プロトタイプではないインスタンスプロパティを持っているか
atai.hasOwnProperty (0);   // true
catai.hasOwnProperty (0);  // true
catai2.hasOwnProperty (0); // false

2   名前: よし : 2007/05/31(木) 01:21  ID:ihmXNzLK sub-t1
丁寧な解説をしていただきありがとうございます。
教えていただいた内容をヒントに考えてみました。
Func.prototype = atai;の意味が理解不足でした。
atai.hasOwnProperty ('getMoji'); // trueとなる。
Func.hasOwnProperty ('getMoji'); // falseとなる。


3   名前: 匿名 : 2007/05/31(木) 01:21  ID:qnouppgv sub-Cz
蛇足ながら、>>1 では回答ポイントを外していた気がするので念のため。

> Func.prototype = atai;の意味

これは、Func.prototype を atai にするということであって、Function.prototype に atai のコピーを代入しているわけではありません。Func.prototype への変更はそのまま atai への変更になりますし、atai への変更はそのまま Func.prototype への変更となります。

言わば、1 つのオブジェクトに対して、「Function.prototype」「atai」という 2 つの名前を付けている(両者は同じオブジェクトを参照している)ということ。



ついでに。ECMAScript では、obj.prop の値を探すとき、

・obj 自身のプロパティ prop
・obj のプロトタイプのプロパティ prop
・obj のプロトタイプのプロトタイプのプロパティ prop
・obj のプロトタイプのプロトタイプのプロトタイプのプロパティ prop
・……

の順で探していき、最終的に見つからなければ undefined を返す。あえて書くなら

・obj.hasOwnProperty (prop)
・obj.constructor.prototype.hasOwnProperty (prop)
・obj.constructor.prototype.constructor.prototype.hasOwnProperty (prop)
・obj.constructor.prototype.constructor.prototype.constructor.prototype.hasOwnProperty (prop)

の順で、最初に true になったオブジェクトの prop の値を返す(もっとも、constructor はすぐ上書きできるので、上記は正確ではない)。ちなみに、JavaScript には __proto__ プロパティがあるので、

・obj.hasOwnProperty (prop)
・obj.__proto__.hasOwnProperty (prop)
・obj.__proto__.__proto__.hasOwnProperty (prop)
・obj.__proto__.__proto__.__proto__.hasOwnProperty (prop)

となる。ECMAScript、JScript にはないが、インスタンスが参照するプロトタイプを変更できるというのは、実のところ非常に便利。

とにかく、インスタンス間で共有したいプロパティはプロトタイプに預けてしまえば良い。まあ、JavaScript の面白いところは、そのプロトタイプをも、プログラム実行中に変更できてしまうことなのですが。

一覧へ戻る