更新答案:
从您下面的评论中,回复我this.log()应该有效的声明:
嗯,事情就是这样。当我在 Child 的测试函数中时,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。
当你需要调用某些东西的父版本时(我称它们为“supercalls”,我认为这不是原始版本),你必须做更多的工作:
我通常通过将父构造函数传递给我用来构建孩子的函数来设置这样的层次结构,例如:
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在代码内部Child编写(我使用Superarg 代替),所以如果我需要 rebase 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将 theChild和Parent原型都作为参数传入,使其使用起来更加简洁(并且由于您可以选择这些参数名称,因此您可以使用任何适合您的术语 - 我使用p正在创建的“类”的原型 [Child在上面],以及pp父母的原型等)。