pumi
pumi

Reputation: 263

Convert an object to a function

How can I pass the variable param to the function? My example doesn't work. The 'run' function throws an error = 'param is not defined'

        var newClass = function (obj) {
            var param = "the param";
            var f = function (param) { };
            f.prototype = obj;
            return nf = new f(param);
        };

        var Runner = {
            run: function () {
                console.log("calling method run " + param);

            }
        };

        var nf = newClass(Runner);
        nf.run();

Upvotes: 0

Views: 104

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075735

It looks like your goal is for newClass to return an object that uses Runner as its prototype and has param as a property. There's a dramatically simpler way to do that; see comments:

var newClass = function(obj) {
    // Create an object using `obj` as its prototype
    var nf = Object.create(obj);

    // Give it a `param` property
    nf.param = "the param";

    // Return it
    return nf;
};

var Runner = {
    run: function() {
        // Note the use of `this `on the next line, to access
        // the property in the instance
        console.log("calling method run " + this.param);
    }
};

var nf = newClass(Runner);
nf.run();

Object.create was added in ES5 (in 2009) and so exists in just about any JavaScript engine that's vaguely recent (so, not the one in IE8); the one-argument version of it above can be shimmed with code very similar to that in your question, see MDN.

On a fully ES5-compliant JavaScript engine, you can use the second argument of Object.create (which cannot be shimmed/polyfilled) to control the enumerability, writability, and configurability of the property:

var newClass = function(obj) {
    // Create and return an object using `obj` as its prototype,
    // with a `param` property:
    return Object.create(obj, {
        param: {
            value: "the param"
        }
    });
};

In that example, param will be non-enumerable, read-only, and not configurable.


Side note: I wouldn't call a function that creates new objects newClass, just FWIW. :-)


In a comment you've said:

My goal is to generate a private variable, only accessible from the inside of Runner. In your example, param is accessible from the outside.

If so, you can't do it with Runner being defined outside the newClass function because, by definition, that's...outside the newClass function.

What you can do is define run within newClass, perhaps having it turn around and call a function on Runner that accepts the param as an argument:

var newClass = function(obj) {
    // The private variable
    var param = "the param";
  
    // Create an object using `obj` as its prototype
    var nf = Object.create(obj);
  
    // Create `run`
    nf.run = function() {
        this.runWithParam(param)
    };

    // Return it
    return nf;
};

var Runner = {
    runWithParam: function(param) {
        console.log("calling method runWithParam " + param);
    }
};

var nf = newClass(Runner);
nf.run();

...or possibly don't use Runner as the prototype at all:

var newClass = function(runner) {
    // The private variable
    var param = "the param";
  
    // Create an object with `run` on it
    var nf = {
        run: function() {
            return runner.runWithParam(param);
        }
    };

    // Return it
    return nf;
};

var Runner = {
    runWithParam: function(param) {
        console.log("calling method runWithParam " + param);
    }
};

var nf = newClass(Runner);
nf.run();

Upvotes: 3

Redu
Redu

Reputation: 26201

You can alsways use a constructor as you have originally intended but if you want to access param from the instantiated objects, then it has to be a property of either the instantiated object or the constructor's prototype. I choose to put it inside the constructor's prototype (i mean to the obj object provided through as an argument, which is later assigned as the constructor function F's prototype).

And of course in order to have access to the properties through object methods we have to refer them with a designation of which parent the method is invoked from. Which is this.

var newClass = function (obj) {
                 var     F = function () { };
                 obj.param = "the param";
                 F.prototype = obj;
                 return new F();
               };

var Runner = { run: function () {
                      console.log("calling method run " + this.param);
                    }
             };

var nf = newClass(Runner);
nf.run();

Upvotes: 0

Related Questions