更新された回答:
以下のコメントから、うまくいくはずの私の声明に返信してthis.log()
ください:
まあ、それが事です。私が子のテスト関数にいるときthis
は空のオブジェクトなので、適切なスコープを取得していない行のどこかを想定しています。
をどのように呼び出しているかは示されていませんがtest
、そこに問題があると思われます。インスタンス経由で呼び出すChild
場合:
var c = new Child();
c.test();
...その後、呼び出し内で子インスタンスになり、そのプロパティを持つオブジェクトをthis
(間接的に) 継承します。Parent.prototype
log
でも、呼び方が大事。たとえば、これは機能しません。
var c = new Child();
var f = c.test;
f();
これを行うと、関数の呼び出し内で、インスタンスではなくthis
グローバル オブジェクトになります (またはundefined
厳密モードの場合) Child
。これは、JavaScript では、this
主に関数の呼び出し方法によって設定され、そのように呼び出しても目的の設定this
にならないためです。
c.test
コールバックとして渡すため、これはコールバックにとって重要です。
someFunctionThatUsesACallback(c.test);
...コールバックするコードが設定されないことを意味this
します。
それを行う必要がある場合は、次のFunction#bind
ことが役立ちます。
var f = c.test.bind(c); // Returns a version of c.test that, when called,
// will have `this` set to `c`
f(); // Works, `this` is the `Child` instance
同様に:
someFunctionThatUsesACallback(c.test.bind(c));
詳細 (私のブログ):
元の回答:
プロトタイプ階層を正しく設定し、それChild.prototype
を持っlog
ていない (そしてlog
インスタンスにプロパティを設定していない) 場合は、問題なく使用できるはずですthis.log();
。できない場合は、階層が正しく設定されていません。
何が機能するのかわかりませんがutil.inherits
、 と の関係Child
をParent
正しく設定することは複雑ではありません。
function Parent() {
}
Parent.prototype.log = function() {
console.log("log called");
};
function Child () {
Parent.call(this);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // This line is largely optional, but a good idea
// Usage
var c = new Child();
c.log(); // "log called"
しかし、プロパティをインスタンスにオーバーライドlog
しChild.prototype
たり割り当てたりして、のバージョンのlog
を使用したい場合は、プロパティがもう参照されないため、そのまま使用することはできません。Parent
log
this.log()
Parent.prototype.log
何かの親バージョンを呼び出す必要がある場合 (私はそれらを「スーパーコール」と呼んでいますが、それはオリジナルではないと思います)、さらに多くの作業を行う必要があります。
私は通常、子を構築するために使用する関数に親コンストラクターを渡すことにより、このような階層を設定します。
var Child = (function(Super) {
var pp = Super.prototype;
function Child() {
}
Child.prototype = Object.create(pp);
Child.prototype.doSomething = function() {
// Call `log` with appropriate `this`
pp.log.call(this);
};
return Child;
})(Parent);
常にそのパターンを使用することで、コードParent
内に記述する必要がなくなります (代わりに arg を使用します)。そのため、 rebase が必要な場合は、関数に渡すものを変更するだけです。Child
Super
Child
これはかなり醜い (たとえば、 が一番下にあるため、 からChild
派生したものであることが一番上では不明確です) し、ボイラープレート コードが含まれているので、毎回書き直す必要はないと思います。そのための簡単なヘルパー スクリプトを作成しました。を呼び出すと、次のようになります。Parent
Parent
Lineage
var Child = Lineage.define(Parent, function(p, pp) {
p.doSomething = function() {
// Call `log` with appropriate `this`
pp.log.call(this);
};
});
とプロトタイプLineage
の両方を引数として渡すことに注意してください。これにより、それらを簡潔に使用できます (そして、これらの引数名を選択できるため、自分に合った用語を使用できます — 私は作成中の「クラス」のプロトタイプに使用します [上記の]、および親のプロトタイプなど)。Child
Parent
p
Child
pp