cor*_*zza 6 javascript oop inheritance prototype
我有一个构造函数,它充当一个超类:
Bla = function(a){this.a = a;}
Run Code Online (Sandbox Code Playgroud)
我把它原型化为包含一个简单的方法:
Bla.prototype.f = function(){console.log("f");
Run Code Online (Sandbox Code Playgroud)
现在new Bla(1).f();将在控制台中记录"f".但是,让我说我需要一个继承自Bla的子类:
Bla2 = function(a)
{
this.base = Bla;
this.base();
}
x = new Bla2(5);
Run Code Online (Sandbox Code Playgroud)
现在,正如所料,x.a给了我5.但是,x.f是undefined!好像Bla2没有从Bla班级继承它!为什么会发生这种情况,我该如何纠正?
T.J*_*der 29
好像
Bla2没有从Bla班级继承它!
对.你没有做任何事情来连接那里的继承,你刚刚创建了一个Bla2被调用的成员,base它是一个Bla实例.base不是JavaScript中的特殊标识符.
在JavaScript中设置继承的典型方法如下所示:
// 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);
};
Run Code Online (Sandbox Code Playgroud)
...... Object.create来自ES5的地方,但它是容易被大部分填充的东西之一.(或者你可以使用一个只做最小的功能而不试图完成所有操作Object.create;见下文.)然后你使用它:
var d = new Derived(4, 2);
d.foo(); // "I'm Base#foo, x = 4"
d.bar(); // "I'm Derived#bar, x = 4, y = 2"
Run Code Online (Sandbox Code Playgroud)
在较旧的代码中,您有时会看到这样的Derived.prototype设置:
Derived.prototype = new Base();
Run Code Online (Sandbox Code Playgroud)
...但是这样做有一个问题:Base可能会进行每个实例的初始化,这不适合整个Derived继承.它甚至可能需要参数(正如我们Base所做的那样;我们会传递x什么?).通过改为成为Derived.prototype一个由它支持的新对象Base.prototype,我们得到了正确的东西.然后我们Base从内部调用Derived以获取每个实例的init.
以上是非常基本的,你可以看到涉及许多步骤.它也很少或根本没有使"超级调用"变得容易和高度可维护.这就是为什么你会看到那么多"继承"脚本,比如Prototype's Class,Dean Edwards'Base2,或者(咳嗽)我自己的Lineage.
如果您不能依赖于在您的环境中使用ES5功能,并且不希望包含具有基本Object.create功能的垫片,则可以在其位置使用此功能:
function simpleCreate(proto) {
function Ctor() {
}
ctor.prototype = proto;
return new Ctor();
}
Run Code Online (Sandbox Code Playgroud)
然后而不是
Derived.prototype = Object.create(Base.prototype);
Run Code Online (Sandbox Code Playgroud)
你做的:
Derived.prototype = simpleCreate(Base.prototype);
Run Code Online (Sandbox Code Playgroud)
当然,你可以做更多的事情来自动挂钩 - 这Lineage基本上就是这样.
......最后:上面我使用匿名函数来简化,例如:
Base.prototype.foo = function() {
// ...
};
Run Code Online (Sandbox Code Playgroud)
...但我不会在我的真实代码中这样做,因为我喜欢帮助我的工具帮助我.所以我倾向于在每个"类"(构造函数和相关原型)周围使用模块模式并使用函数声明(因为我为Web工作,IE7和IE8 仍然存在命名函数表达式的问题.所以,如果我不是'使用Lineage,我会像上面这样做:
// 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);
Run Code Online (Sandbox Code Playgroud)