2014-04-01 76 views
4

我有我要继承从基本功能:添加原型对象

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

错字错误,抱歉。是'concrete2' – Catalin

回答

2

由于Base是一个构造函数,如果你想使用Base.prototype作为它的基础,为Brian Peacock points out below你可以使用构造一个对象:

var concrete2 = new Base(); 
concrete2.notify(); // Works 

如果您想进一步的功能添加到concrete2例如,您可以直接做到这一点:

concrete2.doSomethingElse = function() { /* ... */ }; 

这工作,因为你已经有一个构造函数,所以要建立由construc支持单个对象的最简单方法tor的原型是使用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(); 
    }; 
} 

的一种用途是通过与其他一些代码的标记了一个问题为例:它的单参数版本可以在旧的浏览器,这也是有用的知道它做什么来垫高问题,它使用一种常见但不是理想的方式来设置Concrete1Base之间的继承关系。这是问题的行:

Concrete1.prototype = new Base();     // Not ideal 

的问题是:如果有什么Base做一些事情,应该只有特定实例?例如,假设它接受特定于实例的参数? (这是一个,但只有一个,方法Base可能包含特定于实例的代码。)调用Base几乎从来都不是为其“子类”设置原型的正确方法。相反,您使用Object.create

Concrete1.prototype = Object.create(Base.prototype); // Better 

...通常依次为:

Concrete1.prototype.constructor = Concrete1; 

...只是因为这是规范如何定义函数实例的原型属性(它表示constructor将作为函数,但实际上从未实际使用constructor)。

然后你从Concrete1函数调用Base时,其创建一个实际的实例:

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剧本,这也有助于supercalls和简化的东西公平一点。)

+0

看起来有趣!我将不得不和他们一起玩,以了解他们是如何工作的。 – Catalin

1

你的代码包含两个小错误:

  1. 当定义concrete1你不需要new关键字在函数前面。
  2. 您调用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 
} 

此解决方案可以打破,如果你有,为了引用父类需要一个“干净”的原型链结构的代码。但是,这不是一个正常的用例,并且可能会非常不明确的代码。

+0

@ T.J.Crowder好点,我想我在写答案时处于调试模式。我正在检查这个Object.create业务,它看起来像一个有趣的解决方案。 –