0

From client side (html), form is sent and server side decided which function to run by the one of the select option.

const decideWho = (form) => {
  const choice = form.choice;
  const obj = { key1 : 'func1(form.input1)',
key2 : 'func2(form.input2)'......};
return eval(obj[choice]||obj[default]);
}

Due to some other question, this code was put and Josh Wulf mentioned the danger of using eval.

So here I'm. I couldn't search related to my situation so if you know any answered question, let me know.

My problem is, at first I just put obj's value without quotation mark. Then the disaster happened. When the last line obj[choice]||obj[default] is called, all the functions in the obj are called and some functions were iterating repeatedly. I didn't know what went wrong.

Not only this.

const someFunc = () => {
const a = {
      sourceFolder: "",
      aFolder: "1OoK3j",
      bFolder: "1M_cyv",
      cFolder: "11maBJ",
      dFolder: "1QxA8P",
      eFolder: "11lG"};
    for (let i in a) 
      eval(`var ${i} = getFolder(a['${i}']);`);

..move files to the destination above.
}


const getFolder = id => {
  try {
    if (id) {
      return DriveApp.getFolderById(id);
    } else return DriveApp.getRootFolder();
  } catch (e) {
  // If the folder by the id doesn't exists, return root folder.
    return DriveApp.getRootFolder();
  }
}

I didn't want to declare each folder using same function. So I put them in obj and without eval, iterated.

for (let i in a) var i = getFolder(a[i]);

Here again disaster. When I called aFolder expecting it would return the folder with the id mentioned, it iterates all the folders in the object.

Therefore, for the rescue, values are wrapped around with quotation mark and eval temporally.

What is supposed to be done here?

** Edited ** I'm trying to adopt function constructor.

const aa = form => `id: ${form.id}`;
const bb = () => "I'm b";
const aaa = form => {
  const obj = {
    key1 : 'aa(form)',
    key2 : 'bb'
  };
  const handleIt = new Function('return ' + obj[form.choice])();
  console.log(handleIt());
}
const cc = () => {
  let form = {id: 'student 1', choice: 'key1'};
  aaa(form);
  form = {id: 'student 2', choice: 'key2'};
  aaa(form); 
}

These are simplified only to ask a question but real functions are long. When I perform

form = {id: 'student 2', choice: 'key2'};
  aaa(form); 

It works as expected. But when an argument is supposed to be passed, it says form is not defined.

let form = {id: 'student 1', choice: 'key1'};
  aaa(form);

Where and how do I need to add the arguments if function constructor is the solution?

const aaa = form => {
  const obj = {
    key1 : 'aa(form)',
    key2 : 'bb'
  };
  const handleIt = new Function('return ' + obj[form.choice])();
  console.log(handleIt());
}

Edited 2 I got first one done without eval.

const decideWho = myForm => {
  const obj = {
    key1 : func1(myForm),
    key2 : func2()
  };
  const handleIt = () => {return obj[myForm.choice];};
  console.log(handleIt());
}
Hiru Hira
  • 21
  • 5
  • 2
    Why are you doing `let i` and `var i` in the same expression? Pick a different variable name. – Jeremy Harris Feb 24 '20 at 13:26
  • Sorry. It wasn't var i. It was var `${i}` . And in that way, aFolder, bFolder and so on is declared not i. Also 2nd one isn't too much problematic because this function isn't used often. But first function is important to rescue from eval because that's the main function called every time... – Hiru Hira Feb 24 '20 at 14:12
  • Could you show your current script fully including ``func1`` and `func2`? – TheMaster Feb 24 '20 at 16:39
  • @TheMaster I've solved that one. Just need help for the second one. Thank you. – Hiru Hira Feb 24 '20 at 17:59
  • Ask different questions in different posts. Mixing questions is frowned upon. – TheMaster Feb 24 '20 at 20:08
  • @TheMaster I know but aren't they same? To avoid eval and same behaviour when there is no quotation mark? And both are calling function. Only difference is first one needs to call the function only but second one needs to assign the return value dynamically. I thought it is much better these same question together then separate thread because then I saw people nagging it's duplicate. Anyway if other people also think I have to ask in different post, I'll do. Thanks for checking. – Hiru Hira Feb 25 '20 at 01:58

2 Answers2

1

Well, he fact that you should't use eval does not mean that you can't use new Function instead. In fact, this question has a really good discussion about the differences between both

So.. maybe you should transform your code from

const decideWho = (form) => {
  const choice = form.choice;
  const obj = { 
     key1 : 'func1(form.input1)',
     key2 : 'func2(form.input2)'
  };
  return eval(obj[choice]||obj[default]);
}

To something like:

const decideWho = (form) => {
  const choice = form.choice;
  const obj = { 
     key1 : 'return true',
     key2 : 'return 7'
  };
  return new Function(obj[choice]||obj[default]);
}

Then just call your handler:

 const funcHandler = decideWho(myForm)
 funcHandler()

If you want to pass arguments as well, please refer to this MDN sample

ymz
  • 6,602
  • 1
  • 20
  • 39
  • 1
    Thank you. Your answer gave me heading and I kind of figure out avoiding eval for function calling. I just need to find out the second problem but it must be similar. – Hiru Hira Feb 24 '20 at 18:01
  • Please be more specific about what you are trying to achieve and what is the current problem.. I will try to assist – ymz Feb 25 '20 at 08:34
  • Thank you. It is kind of solved. You can check my code below. I just want to make sure using 'this' has no side effects like eval. – Hiru Hira Feb 25 '20 at 13:39
0

Thanks to stackoverflow and people contributing, I got to solve my problem easily. Both my question was calling a function dynamically and first one was easier as @ymz 's suggestion.

const decideWho = (form) => {
  const choice = form.choice;
  const obj = { key1 : 'func1(form.input1)',
key2 : 'func2(form.input2)'......};
return eval(obj[choice]||obj[default]);
}

Is changed to

const decideWho = myForm => {
  const obj = {
    key1 : ()=> func1(myForm),
    key2 : ()=> func2()
  };
  const handleIt = () => obj[`${myForm.choice}`]();
  return handleIt();
}

And second one also similar but this time the assigning variable is dynamic too. That got solved too by the help of the comment from https://stackoverflow.com/a/28063322/12775761

for (let i in a) 
  eval(`var ${i} = getFolder(a['${i}']);`);

->

for (let i in a) this[`${i}`] = getFolder(a[i]);

If there is no evilness in "this", I'll use in this way. (This is server side function so I can't use window)

Hiru Hira
  • 21
  • 5
  • Witt exactly do you need so many variables? Why `var ${i}`? There's something wrong with your approach. – TheMaster Feb 25 '20 at 07:05
  • @TheMaster It's because the var's name and functions are dynamically chosen at the time of running. – Hiru Hira Feb 25 '20 at 13:37
  • Why can't you do all inside a same function with `switch...case`? – TheMaster Feb 25 '20 at 13:39
  • @TheMaster switch-case had the same problem of iterating all the value not only the called value even with the break and I erased that code. And I prefer object method than switch-case when it has more then 5 to go through. It's much easier to handle and quicker in action at least in this case. And I don't see why you make in one function when each function has different purpose. If all functions are declared in one no one will understand the code. – Hiru Hira Feb 25 '20 at 14:19
  • Could you show the rest of the code in `..move files to the destination above.`? I have trouble visualizing whatever it is that you’re trying to do. – TheMaster Feb 25 '20 at 14:31