2012-02-13 18 views
33

私はそのような例を持っています。なぜプロトタイプからコンストラクタ関数を変更できないのですか?

function Rabbit() { 
    var jumps = "yes"; 
}; 
var rabbit = new Rabbit(); 
alert(rabbit.jumps);     // undefined 
alert(Rabbit.prototype.constructor); // outputs exactly the code of the function Rabbit(); 

私はvar jumpsが公共になるようRabbit()にコードを変更したいです。私はこのようにします:

Rabbit.prototype.constructor = function Rabbit() { 
    this.jumps = "no"; 
}; 
alert(Rabbit.prototype.constructor); // again outputs the code of function Rabbit() and with new this.jumps = "no"; 
var rabbit2 = new Rabbit();    // create new object with new constructor 
alert(rabbit2.jumps);     // but still outputs undefined 

このようにしてコンストラクタ関数のコードを変更できないのはなぜですか?

+0

はあなたの第二のコードは偽、それゆえエラーに評価され、ウサギがジャンプしないと言う - 'this.jumps =「yes」を' – wheresrhys

+0

@wheresrhysを試みるすべての非空の文字列(大きい長さすなわち文字列ゼロよりも)JavaScriptでtrueに評価されます。 – Max

答えて

56

何が起こっている「クラス」のユーザーがインスタンスからのコンストラクタを検出できるようにRabbit.prototype.constructorは、オリジナルのコンストラクタ(function Rabit(){...})への単なるポインタであるということです。したがって、試してみる

Rabbit.prototype.constructor = function Rabbit() { 
    this.jumps = "no"; 
}; 

元のコンストラクタとそのプロトタイプへの参照をリンクしているだけです。

function extend(base, sub) { 

    function surrogateCtor() {} 
    // Copy the prototype from the base to setup inheritance 
    surrogateCtor.prototype = base.prototype; 
    // Tricky huh? 
    sub.prototype = new surrogateCtor(); 
    // The constructor property is set wrong (to the base constructor) 
    // with the above trick, let's fix it 
    sub.prototype.constructor = sub; 
} 

あなたがいることを見ることができます:だから答えは、ノー、あなたはJSで

継承

多くのライブラリは、以下のようなもので継承を実装prototype.constructorに再割り当てすることによって、コンストラクタを変更することはできませんされて上記のコードでは、コンストラクタプロパティを修正する必要がありますが、実際のコンストラクタには影響しません。 JSの継承についての私の記事を参照してくださいhttp://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

コンストラクタを再定義する方法 あなたが本当にコンストラクタを再定義したい場合は、単に行う

var oldProto = Rabbit.prototype; 
Rabbit = function() {...}; 
Rabbit.prototype = oldProto; 
+2

はい、 'prototype.constructor'は何にも影響しません。 – katspaugh

+1

+1すばらしい答え。 – Jivings

0

function Rabbit() { 
    this.jumps = "no"; 
}; 

var rabbit = new Rabbit(); 
alert(rabbit.jumps); // Prints "no" 
+2

プロトタイプの 'jumps'の設定がうまくいかない理由を説明すると、この答えは' + 1'となります。 –

+0

ありがとう、私は元の機能を変更できることを知っています。しかし、プロトタイプから別の方法に変更することが可能かどうかを知りたい。 – Green

1

はこの試してみてください。

Rabbit.prototype = new function(){ 
    this.jumps = "no"; 
}; 

var rabbit2 = new Rabbit();    // create new object with new constructor 
alert(rabbit2.jumps); 

代わりのコンストラクタを設定するあなたは、オブジェクトが作成されたときにこのように、新しい関数であることがプロトタイプオブジェクトを設定したいのプロトタイプを実行し、this.jumpsをnoに設定して、前のコンストラクタによって設定された値をオーバーライドします。

はここに私のjsfiddleです:http://jsfiddle.net/ZtNSV/9/

+1

これは実際には機能しません。プロトタイプ自体のジャンプを設定するのと同じです。あなたは '' Rabbit.prototype = {jumps: 'no'}; ''を呼ぶだけですでにこれを行うことができます。しかし、そのプロトタイプはコンストラクタ関数の何かによってオーバーライドされるため、実際にはしたくないでしょう。 – danShumway

0

、リテラルではありませんからオブジェクトを作成する。これは素晴らしい回避策コンストラクタ関数から。

まず、コンストラクタ内のローカル変数ではなくjumpsメンバをオブジェクトに含めるには、thisというキーワードが必要です。

function Rabbit() { 
    this.jumps = "yes"; 
}; 

var rabbit = new Rabbit(); 
alert(rabbit.jumps);     // not undefined anymore 

そして今、あなたは簡単に今公にあなたが望んでいた道をjumpsにアクセスすることができます。

rabbit.jumps = 'no'; 
alert(rabbit.jumps);     // outputs 'no' 

しかし、まだあなたが別のウサギのオブジェクトを作成する場合、それは最初は右、コンストラクタで定義された「はい」があります?

var rabbit2 = new Rabbit(); 
alert(rabbit.jumps);      // outputs 'no' from before 
alert(rabbit2.jumps);     // outputs 'yes' 

デフォルトのウサギオブジェクトからウサギを作成することができます。具体的なウサギオブジェクト(実装)の値を変更しない限り、その場で変更する場合でも、コンクリートウサギはデフォルトのウサギオブジェクトからデフォルト値を常に持ちます。これはおそらく最高の@Juan Mendesのソリューションとは異なりますが、別の観点を開くことができます。

Rabbit = {jumps : 'yes'}; // default object 

rabbit = Object.create(Rabbit); 
Rabbit.jumps = 'no'; 
rabbit2 = Object.create(Rabbit); 

console.log(rabbit.jumps); // outputs "no" - from default object 
console.log(rabbit2.jumps); // outputs "no" - from default object 

// but... 
rabbit.jumps = 'yes'; 
Rabbit.jumps = 'unknown'; 

console.log(rabbit.jumps); // outputs "yes" - from concrete object 
console.log(rabbit2.jumps); // outputs "unknown" - from default object 
関連する問題