Andrew
Andrew

Reputation: 23

Construct an object with a prototype using Function.apply()

I'm having a bit of a dilemma getting my head around JS' prototypal inheritance. What I'm trying to do is:

  1. Define an object called mod

    var mod = function() {
        function sayGoodbye() {
            alert("Goodbye!");
        }
    
        function saySomethingElse(message) {
            alert(message);
        }
    
        return {
            sayGoodbye: sayGoodbye,
            saySomethingElse: saySomethingElse
        };
    };
    
  2. Define a prototype object called proto

    var proto = {
        sayHello: function() {
            alert("Hello!");
        }
    };
    
  3. Set the prototype of mod to proto

    mod.prototype = proto;
    
  4. Call a function that constructs a new instance of mod with the proto prototype

    function construct(constructor, args) {
    
        function constructorWrapper() {
            return constructor.apply(this, args)
        }
    
        constructorWrapper.prototype = constructor.prototype;
    
        return new constructorWrapper();
    }
    
    var foo = construct(mod, ["Other Message 1"]);
    var bar = construct(mod, ["Other Message 2"]);
    
    console.dir(foo);
    console.dir(bar);
    

The construct function creates a new instance of mod correctly using the apply function but it's prototype is not proto. What am I missing that prevents mod from being constructed with proto as it's prototype?

Here is a fiddle with the above code.

Thanks heaps!!

Upvotes: 0

Views: 40

Answers (1)

Craig Simpson
Craig Simpson

Reputation: 36

The reason the .prototype assignment isn't working for you is because setting the prototype chain like this only works when you use the new operator on a constructor function.

You created a factory function that returns a newly created object. Get rid of the return in mod and use this to attach your method and use new operator when creating instances of mod will make the .prototype assignment work.

This might be confusing so I updated your fiddle: https://jsfiddle.net/6fdo649y/1/

There are several ways to achieve what you are trying to do, but this example explains why you don't see .prototype work.

//Constructor function using this
function Mod(arg1) {
    this.sayGoodbye = function sayGoodbye() {
        alert("Goodbye!");
    }

    this.saySomethingElse = function saySomethingElse(message) {
        alert(message);
    }

    this.arg1 = arg1;
};

var proto = {
    sayHello: function() {
        alert("Hello!");
    }
};

Mod.prototype = proto;

function construct(constructor, args) {

    function constructorWrapper() {
        constructor.apply(this, args)
    }

    constructorWrapper.prototype = constructor.prototype;

    return new constructorWrapper();
}

var foo = construct(Mod, ["Other Message 1"]);
var bar = construct(Mod, ["Other Message 2"]);

console.dir(foo === bar);
console.dir(foo);
console.dir(bar);

edited: added in passing the args through with apply.

Upvotes: 1

Related Questions