更新答案:
从您下面的评论中,回复我的声明 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 属性),那么您应该能够使用@987654348 @ 正好。如果不能,则层次结构设置不正确。
我不知道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"
但是如果你在你的Child.prototype 中覆盖log 或者为实例分配一个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);
通过始终使用该模式,我避免了在 Child 代码中编写 Parent(我使用 Super arg 代替),所以如果我需要变基 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作为父原型等)。