0

I've got an array where strings of expression are listed.

const newPIXI = ["container1 = new PIXI.Container();","container2 = new PIXI.Container();","container3 = new PIXI.Container();"]

I managed to run this with (Function(...newPIXI))()

How can I do this with Ramda? I tried R.forEach , but didn't work.

2
  • what about eval(list.join('\n')) ? Commented Oct 19, 2020 at 14:23
  • Thanks! I assume you have sanitized the string with a regex to be safe like this : stackoverflow.com/a/6479415/13437754 Commented Oct 20, 2020 at 1:08

1 Answer 1

4

These are strings, and not functions. To run them you need to evaluate them using eval() (or Function and then run them). Each string is an expression, and not an actual function. Running the expression will create global variables (container1, container2, and container3).

You've probably heard that eval() is evil. Using eval() is a security risk, and hurts performance, and Function is only slightly less so (read more here):

eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension. More importantly, a third-party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.

Function's advantage is that it runs in the global scope, and can't access variables in the scope it was called in. However, Function still allows running arbitrary code.

Eval example:

const PIXI = {
  Container: function () {
    this.example = 'Container';
  }
};

const newPIXI = ["container1 = new PIXI.Container();","container2 = new PIXI.Container();","container3 = new PIXI.Container();"]

newPIXI.forEach(x => eval(x))

console.log({ container1, container2, container3 });

Function example:

const PIXI = {
  Container: function () {
    this.example = 'Container';
  }
};

const newPIXI = ["container1 = new PIXI.Container();","container2 = new PIXI.Container();","container3 = new PIXI.Container();"]

newPIXI.forEach(x => Function(x)())

console.log({ container1, container2, container3 });

It's better to pass data that tells the browser what you want to do (a command), and not how to do it. Then in the code you can decide how to interpret the command. For example:

const PIXI = {
  Container: function () {
    this.example = 'Container';
  }
};

const newPIXI = [{ type: 'PIXIContainer', name: 'container1' }, { type: 'PIXIContainer', name: 'container2' }, { type: 'PIXIContainer', name: 'container3' }]

const result = {};

newPIXI.forEach(({ type, name }) => {
  switch(type) {
    case 'PIXIContainer':
      result[name] = new PIXI.Container();
      break;
    default:
      throw new Error(`Type ${type} not found`);
  }
})

console.log(result);

Sign up to request clarification or add additional context in comments.

1 Comment

It goes way deeper than I expected. I need to learn more about Javascript now. Thanks for the detail.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.