2016-12-07 4 views
1

私はなぜこのエラーが発生しているのか混乱しています。私はいくつかの啓蒙をしたいです。javascriptオブジェクトのプロトタイプが壊れているようです

function c(me) { this.me = me; } 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); 
 
console.log(d2.speak()); 
 

 
console.log(d.speak()); //returns: TypeError: d.speak is not a function

returns: TypeError: d.speak is not a function

私は明示的にd.prototypeにプロパティspeakを追加しています。実際には、d1d2はどちらもプロトタイプ階層のプロパティ/関数にアクセスできます。それでもdに電話しようとすると、TypeErrorが発生します。私は役に立たないために様々な「調整」を試みました。スコープの問題を排除しようとしてIIFEでさまざまな部分をラップしようとしましたが効果はありませんでした。私は最後の行

console.log(d.speak); //returns: undefined 

undefinedを得るから()を削除しました。これにより、speakdにアクセスできるプロパティ/機能ではないことがわかります。すなわち、 speakblahに変更し、コンソールに同じundefinedを記録してください。

console.log(d.blah); //returns: undefined 

私は、目の新しいセットには明白かもしれない小さなものが欠けていることを知っています。

+1

'd.speak()'文句を言わない仕事は 'D 'のプロトタイプオブジェクトに'話す() '関数を添付しているので、関数ではなく、 'd'関数自体ではありません。ですから、 'speak()'関数を 'd.speak = function(){}'のように 'd'自身につけるか、' d.prototype.speak() 'を呼んで呼び出す必要があります。 –

+1

d.speak()が何を返すと思いますか? – Oriol

+0

@Oriol、 'こんにちは、私は未定です.'私の期待でした。 – ppovoski

答えて

3

これが期待されています。ほとんどの場合、コンストラクタはそれ自身のインスタンスではありません。コンストラクタは、インスタンスで利用可能なメソッドをprototypeに定義しますが、このprototypeはコンストラクタ自体の[[Prototype]]チェーンには表示されません。

理由は単純である:

  • オブジェクトは、単一の[] [プロトタイプ]を有することができます。

  • コンストラクタは関数なので、[[Prototype]]チェーンではFunction.prototypeでなければなりません。これにより、コンストラクタでcallまたはapplyのような関数メソッドを呼び出すことができます。彼らは機能していないので

  • インスタンスは、コンストラクタのprototypeからではなく、Function.prototypeから継承しなければなりません。

したがって、一般にコンストラクタはprototypeから継承できません。組み込みの例外は、FunctionObjectです。

つまり、上の2番目または3番目の不変量を取り除くことができます。そうすれば正常に動作させることができますが、通常は人々が依存しているため、[[Prototype]]の変更はパフォーマンスが悪いため、悪い考えです。

function c(me) { this.me = me; } 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 
Object.setPrototypeOf(d, d.prototype); 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); // "Hello, I am d1." 
 
console.log(d2.speak()); // "Hello, I am d2." 
 
console.log(d.speak()); // "Hello, I am undefined." 
 

 
console.log(d.call); // undefined :(

function c(me) { this.me = me; } 
 
c.prototype = Object.create(Function.prototype); 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 
Object.setPrototypeOf(d, d.prototype); 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); // "Hello, I am d1." 
 
console.log(d2.speak()); // "Hello, I am d2." 
 
console.log(d.speak()); // "Hello, I am undefined." 
 

 
console.log(d1 instanceof Function); // true Huh????

+0

+1しかし、これは本当に悪い考えです:-) – Bergi

+0

@Bergi確かに "*不変量を取り除く*を選択した後に免責事項を追加する必要があります!私は警告するが、忘れて、感謝したかった。 – Oriol

+0

それを釘付け!よくやった! – ppovoski

1

変数dコンストラクタです。そのコンストラクタのprototypeプロパティを使用して、インスタンスが継承するプロトタイプオブジェクトにアクセスします。

console.log(d.prototype.speak) //=> [Function] 

デモ:

function c(me) { this.me = me; } 
 
c.prototype.identify = function() { return "I am " + this.me; }; 
 

 
function d(me) { c.call(this, me); } 
 
d.prototype = Object.create(c.prototype); 
 
d.prototype.speak = function() { return "Hello, " + this.identify() + "." }; 
 

 
var d1 = new d("d1"); 
 
var d2 = new d("d2"); 
 

 
console.log(d1.speak()); 
 
console.log(d2.speak()); 
 

 
console.log(d.prototype.speak) //=> [Function]

+0

関数に使われる変数 'd'はプロトタイプに使われた' d'と同じではないと言っていますか? – ppovoski

+1

関数 'd'は、プロトタイプでは決してコンストラクタとして使用されませんでした。 JavaScriptのすべての関数は、独自のプロトタイプオブジェクトを持ちます。 'd1'と' d2'のプロトタイプは 'd.prototype'です。それについて考えるもう一つの方法: 'new d 'を呼び出すたびに、本当に起こっているのは' Object.create(d.prototype) 'です。 – gyre

関連する問題