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.

Rio
  • 123
  • 7

1 Answers1

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);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • It goes way deeper than I expected. I need to learn more about Javascript now. Thanks for the detail. – Rio Oct 19 '20 at 13:40