0

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();
pumi
  • 263
  • 1
  • 7
  • 2
    You should read [What is the scope of variables in JavaScript?](http://stackoverflow.com/q/500431/218196). `var f = function (param) { };` should raise some big question marks. You declare a parameter but are not doing anything with it. Also, what's your end goal with all this? Why don't you just make `run` accept a parameter or at least have a simple factory function that returns a new `Runner` object... – Felix Kling Jun 06 '16 at 15:13
  • @FelixKling It looks like OP is using [Crockfords prototypal inheritance function](http://javascript.crockford.com/prototypal.html) – evolutionxbox Jun 06 '16 at 15:26
  • I'm working on my own module library. This library should convert an object literal into a function. My goal in this question is: convert the this-variables into private variables.(var param=...). I have to use an old style, because it's for an Rhino-engine that works with javascript. Most new features doesn't work. – pumi Jun 06 '16 at 16:18

2 Answers2

3

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();
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I think the OP was trying to use [Crockford's prototypal inheritance function](http://javascript.crockford.com/prototypal.html). It's almost 10 years old now! – evolutionxbox Jun 06 '16 at 15:27
  • @evolutionxbox: Very possible, as that was the inspiration for `Object.create`. :-) – T.J. Crowder Jun 06 '16 at 15:29
  • Indeed. I remember him pushing it's use about 6 years ago. Now it seems he doesn't use it at all. – evolutionxbox Jun 06 '16 at 15:31
  • @evolutionxbox: `Object.create`? Surely he does (or something functionally similar), since he never uses `new` anymore...? (Then again, why Crockford doesn't just go off and write himself a functional language that transpiles to JavaScript, I don't know... :-) ) – T.J. Crowder Jun 06 '16 at 15:41
  • 1
    He stopped using it "years ago". http://xahlee.info/js/js_Douglas_Crockford_the_better_parts.html - See the video at 19:00 – evolutionxbox Jun 06 '16 at 16:01
  • 1
    @evolutionxbox: Ah, I'd heard about the `this` thing. Hadn't made the jump to that meaning he's basically abandoned inheritance. Again: Dude, just create your own language. :-) – T.J. Crowder Jun 06 '16 at 16:08
  • @T.J.Crowder Thanks for the example. My goal is to generate a private variable, only accessible from the inside of Runner. In your example, param is accessible from the outside – pumi Jun 06 '16 at 16:29
  • @pumi: That would have been really useful information to put in the question. You can't do that and have `param` accessible to `Runner`, because `Runner` is, by definition, outside the function containing the truly private `param`. Instead, just define `run` within the function. – T.J. Crowder Jun 06 '16 at 16:34
  • @T.J.Crowder: Ok you'r right. Next time I'l explain it better. Thanks. – pumi Jun 06 '16 at 16:44
  • @pumi: I've added a couple of options at the end of the answer, in case they're useful. – T.J. Crowder Jun 06 '16 at 16:52
  • @T.J.Crowder: Thanks for the options. – pumi Jun 07 '16 at 04:27
  • @T.J.Crowder: Question about your side note. How would you describe the function call. Runner is an object. After the create it is also an object. – pumi Jun 07 '16 at 04:35
  • @pumi: Probably `createRunner`, since it creates specific runners. – T.J. Crowder Jun 07 '16 at 07:14
  • In this case you'r right, but it's a part from a bigger project and this function should be an generic function with a generic name. – pumi Jun 07 '16 at 08:09
  • @pumi: Hmmm, I'd probably go with `createObject` or `createInstance` or even just `create`, then. I'm just saying that since it doesn't create a *class* (in JavaScript: a constructor function and associated prototype), `newClass` isn't the name I'd use. But naming is very subjective. :-) – T.J. Crowder Jun 07 '16 at 08:13
  • 1
    @T.J.Crowder: createInstance looks nice for me. Thanks. – pumi Jun 07 '16 at 08:22
0

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();
Redu
  • 25,060
  • 6
  • 56
  • 76