问题描述
我有一个构造函数,它充当超类:
I have one constructor function, which acts as a superclass:
Bla = function(a){this.a = a;}
我将其原型化为包含一个简单的方法:
I prototype it to include a simple method:
Bla.prototype.f = function(){console.log("f");
现在新 Bla(1).f();
将在控制台中记录f。但是,让我说我需要一个继承自Bla的子类:
And now new Bla(1).f();
will log "f" in the console. But, lets say that I need a subclass that inherits from Bla:
Bla2 = function(a)
{
this.base = Bla;
this.base();
}
x = new Bla2(5);
现在,按预期, xa
给了我 5
。但是, x.f
是 undefined
!好像 Bla2
没有从 Bla
类继承它!为什么会发生这种情况?如何更正?
Now, as expected, x.a
gives me 5
. But, x.f
is undefined
! Seems like Bla2
didn't inherit it from the Bla
class! Why is this happening and how do I correct it?
推荐答案
对。你没有做任何事情来连接那里的继承,你刚刚创建了一个 Bla2
的成员,名为 base
是一个 Bla
实例。 base
不是JavaScript中的特殊标识符。
Right. You haven't done anything to hook up inheritance there, you've just created a member of Bla2
called base
which is a Bla
instance. base
is not a special identifier in JavaScript.
在JavaScript中设置继承的典型方法如下所示:
The typical way to set up inheritance in JavaScript looks like this:
// The base constructor function
function Base(x) {
// Base per-instance init
this.x = x;
}
// An example Base function
Base.prototype.foo = function() {
console.log("I'm Base#foo, x = " + this.x);
};
// The Derived constructor function
function Derived(x, y) {
// Normally you need to call `Base` as it may have per-instance
// initialization it needs to do. You need to do it such that
// within the call, `this` refers to the current `this`, so you
// use `Function#call` or `Function#apply` as appropriate.
Base.call(this, x);
// Derived per-instance init
this.y = y;
}
// Make the Derived.prototype be a new object backed up by the
// Base.prototype.
Derived.prototype = Object.create(Base.prototype);
// Fix up the 'constructor' property
Derived.prototype.constructor = Derived;
// Add any Derived functions
Derived.prototype.bar = function() {
console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y);
};
...其中来自ES5,但它是可以很容易地大部分填充的东西之一。 (或者你可以使用一个只做最低限度而不试图完成所有 Object.create
的函数;见下文。)然后你使用它:
...where Object.create
is from ES5, but it's one of the things that can easily be mostly shimmed. (Or you can use a function that only does the bare minimum without trying to do all of Object.create
; see below.) And then you use it:
var d = new Derived(4, 2);
d.foo(); // "I'm Base#foo, x = 4"
d.bar(); // "I'm Derived#bar, x = 4, y = 2"
|
在旧代码中,您有时会看到派生.prototype
设置如下:
In older code you sometimes see the Derived.prototype
set up like this instead:
Derived.prototype = new Base();
...但这样做有问题: Base
可以进行每个实例的初始化,这不适合继承的 Derived
的全部内容。它甚至可能需要参数(因为我们的 Base
会这样做;我们将为 x
传递什么?)。通过改为使 Derived.prototype
成为由 Base.prototype
支持的新对象,我们得到正确的东西。然后我们从 Derived
中调用 Base
来获取每个实例的初始化。
...but there's a problem with doing it that way: Base
may do per-instance initialization which isn't appropriate for the entirety of Derived
to inherit. It may even require arguments (as our Base
does; what would we pass for x
?). By instead making Derived.prototype
just be a new object backed by the Base.prototype
, we get the correct stuff. Then we call Base
from within Derived
to get per-instance init.
以上是非常基本的,你可以看到涉及许多步骤。它也很少或根本没有使超级调用变得容易和高度可维护。这就是你看到那么多继承脚本的原因,比如Prototype的 Class
,Dean Edwards的Base2,或(cough)我自己的。
The above is very basic and as you can see involves a number of steps. It also does little or nothing to make "supercalls" easy and highly-maintainable. That's why you see so many "inheritance" scripts out there, like Prototype's Class
, Dean Edwards' Base2, or (cough) my own Lineage
.
如果您不能依赖环境中的ES5功能,并且不希望包含一个基于 Object.create的基础知识的垫片
,您可以在其位置使用此功能:
If you can't rely on having ES5 features in your environment, and don't want to include a shim that does the basics of Object.create
, you can just use this function in its place:
function simpleCreate(proto) {
function Ctor() {
}
ctor.prototype = proto;
return new Ctor();
}
然后代替
Derived.prototype = Object.create(Base.prototype);
你要这样做:
Derived.prototype = simpleCreate(Base.prototype);
当然,你可以做更多事情来自动挂钩事情 —全部 Lineage
基本上都是。
Of course, you can do more to automate hooking things up — which is all Lineage
basically does.
......最后:上面我简单地使用了匿名函数,例如:
...and finally: Above I've used anonymous functions for simplicity, e.g.:
Base.prototype.foo = function() {
// ...
};
...但我在实际代码中没有这样做,因为。所以我倾向于在每个类(构造函数和相关原型)周围使用模块模式并使用函数声明(因为我在网上工作,而IE7和IE8 的命名函数表达式。所以,如果我没有使用 Lineage
,我会像这样做:
...but I don't do that in my real code, because I like to help my tools help me. So I tend to use the module pattern around each "class" (constructor function and associated prototype) and use function declarations (since I do work for the web, and IE7 and IE8 still have problems with named function expressions. So if I weren't using Lineage
, I'd do the above like this:
// Base
(function(target) {
// Base constructor
target.Base = Base;
function Base(x) {
// Base per-instance init
this.x = x;
}
// An example Base function
Base.prototype.foo = Base$foo;
function Base$foo() {
console.log("I'm Base#foo, x = " + this.x);
}
})(window);
// Derived
(function(target, base) {
// The Derived constructor function
target.Derived = Derived;
function Derived(x, y) {
// Init base
base.call(this, x);
// Derived per-instance init
this.y = y;
}
// Make the Derived.prototype be a new object backed up by the
// Base.prototype.
Derived.prototype = Object.create(base.prototype);
// Fix up the 'constructor' property
Derived.prototype.constructor = Derived;
// Add any Derived functions
Derived.prototype.bar = Derived$bar;
function Derived$bar() {
console.log("I'm Derived#bar, x = " + this.x + ", y = " + this.y);
}
})(window, Base);
......或类似的东西。 |
...or something like that. Live copy | source
这篇关于对象不继承原型函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!