I want to create three functions out of one javascript string containing the js source code.

Lets say i have the following code as one string:

"
function func1()
{
    console.log('This comes from func1')
}

function func2()
{
    console.log('This comes from func2')
}

function func3()
{
    console.log('This comes from func3')
}
"

Now i want to create these three function as javascript functions and attach them to an object, like:

object1.func1 = function func1(){...}
object1.func2 = function func2(){...}

I have a lot of objects and want to be able to attach a script file that contains these three functions func1, func2 and func3. The script file can contain other functions too, but these getting called by one of the three functions. So a script file for an object could look like as follows:

"
// Main functions of a script file
// A script file MUST contain these three functions

function func1()
{
    console.log('This comes from func1')
    userFunc1();
    // do some user code
}

function func2()
{
    console.log('This comes from func2')
    userFunc2();
    // do some user code
}

function func3()
{
    console.log('This comes from func3')
    userFunc3();
    userFunc4();
    // do some user code
}


// User functions
// these are optional

function userFunc1()
{
    // do stuff
}

function userFunc2()
{
    // do stuff
}

function userFunc3()
{
    // do stuff
}

function userFunc4()
{
    // do stuff
}

"

I have no problem creating a function when the string only contains one function, like as follows:

var jsCode = "(function func1(){console.log('This comes from func1')})";
var script=new Function (jsCode);
script();

My problem is how to parse two or more functions out of one string and create these functions accordingly?

I don't want to use any libraries, just pure javascript and I don't want to use eval as it seems to be horribly slow.

Can somebody help me with this problem?

1 Answers

2
trincot On Best Solutions

When running in a browser, you can dynamically add a script element and execute it with createContextualFragment:

function executeCode(code) {
    document.head.appendChild(
        document.createRange().createContextualFragment('<script>' + code + '<\/script>')
    );
}

// Demo
const code = `
function func1()
{
    console.log('This comes from func1')
}

function func2()
{
    console.log('This comes from func2')
}

function func3()
{
    console.log('This comes from func3')
}`;

executeCode(code);

func1();
func2();
func3();

Getting functions loaded as object members

After the update of the question, the functions must be object members. In that case I would request that the provided code follows this format:

({
    func1()
    {
        console.log('This comes from func1')
    },
    func2()
    {
        console.log('This comes from func2')
    },
    func3()
    {
        console.log('This comes from func3')
    }
})

Then you can use eval to get this object expression into a variable:

const code = `
    ({
        func1()
        {
            console.log('This comes from func1')
        },
        func2()
        {
            console.log('This comes from func2')
        },
        func3()
        {
            console.log('This comes from func3')
        }
    })
`;

const obj = eval(code);

obj.func1();
obj.func2();
obj.func3();

A less intrusive change to the code format would be to make it an array expression:

const code = `
    [
        function func1()
        {
            console.log('This comes from func1')
        },
        function func2()
        {
            console.log('This comes from func2')
        },
        function func3()
        {
            console.log('This comes from func3')
        }
    ]
`;

const obj = Object.fromEntries(eval(code).map(f => [f.name, f]));

obj.func1();
obj.func2();
obj.func3();

When the code cannot be changed

If your current syntax cannot be changed, then I would suggest to do a string-replacement on it so to arrive at the above-mentioned array syntax:

const code = `
function func1()
{
    console.log('This comes from func1')
}

function func2()
{
    console.log('This comes from func2')
}

function func3()
{
    console.log('This comes from func3')
}`;

const array = "[" + code.replace(/}(\s*function\b)/g, "},$1") + "]";

const obj = Object.fromEntries(eval(array).map(f => [f.name, f]));

obj.func1();
obj.func2();
obj.func3();

Obviously, such a string replacement has some drawbacks, as the code may have nested functions, and those should not get the additional comma (although it would not always break the code). One can also imagine code with string literals that have the sequence } function in them, ...etc, ...etc.