0

I need to run bunch of scripts saved in text. I need to convert them to JavaScript during runtime and it may have some calls to some functions within that class to get some data, like shown below. Basically I need to expose functions of the class to those scripts being run in one of the function of the same class. It works fine as long as I do not make calls to randomNumbers() function and hard code some numbers. I'll appreciate any feedback on this. thank you,

   var config = {
    minX: 1,
    maxX: 10,
    get randomIntFromInterval() {
        return (() =>
            Math.floor(Math.random() * (this.maxX - this.minX + 1) + this.minX)).bind(
                config
            );
    },
};
        
        
        export const executeFns = () => {
            let edit = `
            let a = randomIntFromInterval();
            let b = randomIntFromInterval();
            if (a> b) {
            console.log('a is bigger than b')
            } else if (b>a) {
            console.log('b is bigger than a')
            }
            console.log('a',a );
            console.log('b',b )`;
        
            var f4 = NamedFunction('fancyname', [], edit, config);
            f4();
        };
        
            export function NamedFunction(name, args, body, scope, values) {
                if (typeof args == 'string') {
                    values = scope;
                    scope = body;
                    body = args;
                    args = [];
                }
            
                if (!Array.isArray(scope) || !Array.isArray(values)) {
                    if (typeof scope == 'object') {
                        var keys = Object.keys(scope);
                        values = keys.map(function (p) {
                            return scope[p];
                        });
                        scope = keys;
                    } else {
                        values = [];
                        scope = [];
                    }
                }
                return Function(
                    scope,
                    'function ' +
                        name +
                        '(' +
                        args.join(', ') +
                        ') {\n' +
                        body +
                        '\n}\nreturn ' +
                        name +
                        ';'
                ).apply(null, values);
            }
  • [`new Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function) takes the body of the function as an argument, the definition wrapper is not a part of the body. – Teemu Jun 27 '21 at 19:30
  • I also can't see any reason, why the function in the example should be dynamically created, there's nothing dynamic in that function. – Teemu Jun 27 '21 at 19:38
  • `randomNumbers` is a method of an instance, not a globally available function. Though since it doesn't use any instance properties (or the `this` keyword), it really *shouldn't* be a class method; maybe you shouldn't be using a `class` here at all. – Bergi Jun 27 '21 at 19:46
  • Have a look at [this code](https://stackoverflow.com/a/24032179/1048572) which lets you put arbitrary values in the scope of the new function definition dynamically. – Bergi Jun 27 '21 at 19:48
  • @Teemu I would think the `const edit` is only a simplification in the example code, and assume it's actually dynamically loaded in from files in the real code. – Bergi Jun 27 '21 at 19:50
  • @Teemu, you are correct in your understanding that it is simplification of the concept. I real situation there will be bunch of JavaScript code stored in a external source and would run on some data and may need some data coming from JavaScript function coded in class/modules (doesn't have to be in a class). Can I make a call from string based functions to functions stored in other modules/class? – Rahul Joshi Jun 27 '21 at 20:11
  • @Bergi, Thanks for sharing the link for the code. It is useful. However, I'm interested in being able to make a call to module/class functions from that function. Appreciate your help. – Rahul Joshi Jun 27 '21 at 20:14
  • @RahulJoshi You need to make them available explicitly, there is no way around this. Use the approach shown in the link (you can ignore the `name, args, body` when only running code) – Bergi Jun 27 '21 at 20:26
  • @Bergi, is it possible to expose whole module or class in the function creation itself like i.e. stringToFunctionAndExecute() { const edit = ` import someclass; let a =someclass.randomNumbers(); let b = someclass.randomNumbers(); if (a> b) { console.log('a is bigger than b') } else if (b>a) { console.log('b is bigger than a') }`; var stringFunction = `(function() { ${edit} })()`; } } – Rahul Joshi Jun 27 '21 at 20:32
  • @RahulJoshi In the code I linked, `scope` is an object. You can just pass your class instance or module namespace there. No, an `import` declaration won't work in a function. – Bergi Jun 27 '21 at 21:16
  • @Bergi, thanks a ton for providing great help. I was able to execute function by passing module namespace. However, passing class instance doesn't work. I see why but I have no clue how to get around this. – Rahul Joshi Jun 28 '21 at 19:59
  • @Bergi, I'm finding it difficult to properly format the appropriate code for the review here. Is there any way I can show the snippet of the code to you for your advice. – Rahul Joshi Jun 28 '21 at 20:20
  • @RahulJoshi You can [edit] your question, or even [write your own answer](https://stackoverflow.com/help/self-answer) with a proposed solution, and use code formmating in there. – Bergi Jun 28 '21 at 20:26
  • @Bergi, I just updated the code. It works fine if I pass module namespace in place of `objt` carrying same function. However with the class object it won't work. I modified top `if` part of your function. It wasn't compiling the way it was put on the site. I hope I didn't mess it up. – Rahul Joshi Jun 28 '21 at 20:39
  • Ah, `Object.keys()` doesn't list properties inherit from the prototype, such as the `randomIntFromInterval` method of your class instance. Either don't use a `class` but an object literal (you're not using `this` in those methods anyway, right?), or use a `for…in` loop or something similar that considers inherited properties. – Bergi Jun 28 '21 at 20:51
  • Thanks @Bergi for your insight. However, If I try to access object literal's properties in it's function (code is modified to show current situation) it has to be getter so that `this` keyword can access appropriate properties. But if I make that function as getter than `NamedFunction` doesn't find `randomIntFromInterval` function. If I keep it normal function then `randomIntFromInterval` function can't access 'min' & 'max' properties. Would you have any idea how to go about it. Thanks... – Rahul Joshi Jun 29 '21 at 12:58
  • You could return an arrow function from the getter, e.g. `get randomInt() { return () => Math.random() * this.size; }`. Or you just `.bind()` the functions that you want to pass in the `scope` object. – Bergi Jun 29 '21 at 13:15
  • thanks a ton @Bergi. I got it to work with getter function returning arrow function bound to name space. Solution is posted in the updated question. I do not see post your answer button. – Rahul Joshi Jun 29 '21 at 19:00

0 Answers0