Pregunta

I have a base function which i want to inherit from:

function Base() {
    this._dummy = 1;
};
Base.prototype.notify = function () {
    alert("Notify");
};

Creating another constructor class works:

function Concrete1() {};
Concrete1.prototype = new Base();
var concr1 = new Concrete1();
concr1.notify(); // alerts "Notify"

Declaring an object like this doesn't work, probably because the object doesn't have a prototype

var concrete2 = new function () {};
concrete2.prototype = new Base();
concrete2.notify(); // doesn't work

I don't want to create Concrete2 constructor because it will only be one instance of it.

Can i make "inheritance" work with new function() method?

¿Fue útil?

Solución

Since Base is a constructor function, if you want a single object that uses Base.prototype as its base, as Brian Peacock points out below you can just use the constructor:

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

If you want to add further features to the concrete2 instance, you can do that directly:

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

That works because you already have a constructor function, so the simplest way to create a single object backed by that constructor's prototype is to use the new operator.

Sometimes, though, you want to use an object when either it's not associated with a constructor function, or you have a reason for not wanting to call that constructor function. In those situations (I'll give an example of one below), you can use Object.create, which is in ES5 and which can be partially shimmed in older browsers:

// Creates an object backed by Base.prototype without calling Base
var concrete2 = Object.create(Base.prototype);
concrete2.notify(); // Works

Object.create creates a new object directly, setting its prototype to the object you pass into it. The single-argument version of it can be shimmed on older browsers, which is also useful for knowing what it does:

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

One use of this is exemplified by flagging up an issue with some of the other code in the question, which uses a common, but not ideal, means of setting up inheritance between Concrete1 and Base. This is the problematic line:

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

The issue is: What if Base does something that should only be instance-specific? For instance, suppose it accepts instance-specific arguments? (Which is one, but only one, way Base could have instance-specific code in it.) Calling Base is almost never the correct way to set up the prototype for a "subclass" of it. Instead, you use Object.create:

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

...usually followed by:

Concrete1.prototype.constructor = Concrete1;

...just because that's how the spec defines the prototype property of function instances (it says constructor will be the function, but then never actually uses constructor for anything).

Then you call Base from the Concrete1 function when its creating an actual instance:

function Concrete1(any, necessary, args) {
    Base.call(this, any, necessary); // For example
    this.args = args;                // For example
}

Complete 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...*/

...and so on. (Or use a helper script like my Lineage script, which also helps with supercalls and simplifies things a fair bit.)

Otros consejos

Your code contains two small errors:

  1. When defining concrete1 you do not need the new keyword in front of the function.
  2. The way you called concrete2.notify() will not work because you don't have an instance of the new class. concrete2.prototype.notify() will work, as will new concrete2().notify().

See this JSFiddle for a working version (with some renaming for clarity).

Edit/Rewrite:

Thank you to @T.J.Crowder for pointing out that @RaraituL was looking for a singleton that inherits the base class.

In most cases you could simply create an instance of Base and modify it's the properties that you wish to add/overwrite. While this will not provide prototypical inheritance, it will likely achieve the desired result:

function Base() {
    this._dummy = 1;
};

Base.prototype.notify = function () {
    alert("Notify");
};

Concrete1 = new Base();

//My Extension of Base
Concrete1.foo = function() {
    //Some method
}

This solution could break down if you have code that expects a "clean" prototype chain structure in order to reference parent classes. However, that is not a normal use case and would likely be very unclear code as well.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top