将原型添加到对象

时间:2014-04-01 07:13:51

标签: javascript prototype

我有一个我想继承的基本功能:

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()方法?

2 个答案:

答案 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();
    };
}

通过标记问题中某些其他代码的问题来举例说明这一点,该问题使用了一种常见但不理想的方法来设置Concrete1Base之间的继承。这是有问题的一行:

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)

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

  1. 定义concrete1时,您不需要在函数前面使用new关键字。
  2. 您调用concrete2.notify()的方式无效,因为您没有新类的实例。 concrete2.prototype.notify()将会有效,new concrete2().notify()
  3. 有关正常工作的版本,请参阅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
    }
    

    如果您的代码需要“干净”的原型链结构以引用父类,则此解决方案可能会崩溃。但是,这不是一个正常的用例,也可能是非常不清楚的代码。