我有一个我想继承的基本功能:
function Base() {
this._dummy = 1;
};
Base.prototype.notify = function () {
alert("Notify");
};
创建另一个构造函数类:
function Concrete1() {};
Concrete1.prototype = new Base();
var concr1 = new Concrete1();
concr1.notify(); // alerts "Notify"
声明这样的物体并不起作用,可能是因为物体没有原型
var concrete2 = new function () {};
concrete2.prototype = new Base();
concrete2.notify(); // doesn't work
我不想创建Concrete2
构造函数,因为它只是它的一个实例。
我可以做"继承"使用new function()
方法?
答案 0 :(得分:2)
由于Base
是一个构造函数,如果你想要一个以Base.prototype
为基础的单个对象,Brian Peacock points out below你可以使用构造函数:
var concrete2 = new Base();
concrete2.notify(); // Works
如果您想为concrete2
实例添加更多功能,可以直接执行此操作:
concrete2.doSomethingElse = function() { /* ... */ };
这是因为你已经有了一个构造函数,所以创建由该构造函数原型支持的单个对象的最简单方法是使用new
运算符。
但是,有时候,如果某个对象与构造函数没有关联,或者您有理由不想调用该构造函数,则需要使用该对象。在这些情况下(我将给出下面一个示例),您可以使用Object.create
,它位于ES5中,可以在旧浏览器中部分填充:
// Creates an object backed by Base.prototype without calling Base
var concrete2 = Object.create(Base.prototype);
concrete2.notify(); // Works
Object.create
直接创建一个新对象,将其原型设置为传递给它的对象。它的单参数版本可以在旧浏览器上填充,这对于了解它的作用也很有用:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The two-argument version of Object.create cannot be shimmed.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
通过标记问题中某些其他代码的问题来举例说明这一点,该问题使用了一种常见但不理想的方法来设置Concrete1
和Base
之间的继承。这是有问题的一行:
Concrete1.prototype = new Base(); // Not ideal
问题是:如果Base
执行的操作应该只是特定于实例的,该怎么办?例如,假设它接受特定于实例的参数? (这是一个,但只有一个,方式Base
可以包含特定于实例的代码。)调用Base
几乎不是为#34;子类设置原型的正确方法&# 34;它的。相反,您使用Object.create
:
Concrete1.prototype = Object.create(Base.prototype); // Better
...通常接着是:
Concrete1.prototype.constructor = Concrete1;
...只是因为规范如何定义函数实例的原型属性(它表示constructor
将是函数,但实际上从未实际使用constructor
。
然后在创建实际实例时从Base
函数调用Concrete1
:
function Concrete1(any, necessary, args) {
Base.call(this, any, necessary); // For example
this.args = args; // For example
}
完整示例:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
};
/* ...further Person-specific functions put on Person.prototype here...*/
function Employee(firstName, lastName, jobTitle) {
Person.call(this, firstName, lastName);
this.jobTitle = jobTitle;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
/* ...Employee-specific functions put on Employee.prototype here...*/
function Manager(firstName, lastName, jobTitle) {
Employee.call(this, firstName, lastName);
this.jobTitle = jobTitle;
}
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
/* ...Manager-specific functions put on Manager.prototype here...*/
......等等。 (或者使用像我的Lineage
脚本这样的帮助脚本,这也有助于超级调用并简化事情。)
答案 1 :(得分:1)
您的代码包含两个小错误:
concrete1
时,您不需要在函数前面使用new
关键字。concrete2.notify()
的方式无效,因为您没有新类的实例。 concrete2.prototype.notify()
将会有效,new concrete2().notify()
。有关正常工作的版本,请参阅this JSFiddle(为清晰起见,请进行一些重命名)。
修改/重写强>:
感谢@ T.J.Crowder指出@RaraituL正在寻找一个继承基类的单例。
在大多数情况下,您只需创建Base
的实例并修改它是您要添加/覆盖的属性。虽然这不会提供原型继承,但它可能会达到预期的结果:
function Base() {
this._dummy = 1;
};
Base.prototype.notify = function () {
alert("Notify");
};
Concrete1 = new Base();
//My Extension of Base
Concrete1.foo = function() {
//Some method
}
如果您的代码需要“干净”的原型链结构以引用父类,则此解决方案可能会崩溃。但是,这不是一个正常的用例,也可能是非常不清楚的代码。