Angular/Typescript Eval and this
If you do something like:
this.TestClass.call("this");
and in the TestCalss:
console.log(eval(pString));
You will find that it logs as the window
object. The string this
won't take the context with itself. If you would had logged, window.arrTest1
, this would had given you the desired result.
So...
You need to pass the context:
this.TestClass.Run.call(this, "this.arrTest1 = [1]");
And in your TestCalss
TestClass = {
Run : (pString) => {
return eval(pString)
}
};
Why does eval.call(this, pString) not work?
There is something different about how eval()
works. eval()
is not a real javascript function. As answered here: How override eval function in javascript?
As you have already tried in your question, you did something like:
(0, eval)(pString); // this is an indirect call to eval
What is an indirect call??
According to ES5, all of these are indirect calls and should execute code in global scope
The gloabl scope in your case will be nothing, typescript by default doesn't provide a global scope. (As far I know)
There's a very comprehensive description about eval
written here:
http://perfectionkills.com/global-eval-what-are-the-options/
According to the above link, following are some of the examples of indirect eval
calls :
(1, eval)('...')
(eval, eval)('...')
(1 ? eval : 0)('...')
(__ = eval)('...')
var e = eval; e('...')
(function(e) { e('...') })(eval)
(function(e) { return e })(eval)('...')
(function() { arguments[0]('...') })(eval)
this.eval('...')
this['eval']('...')
[eval][0]('...')
eval.call(this, '...') <-- This is your case.
eval('eval')('...')
Another paragraph from the article:
Not understanding what’s going on, some people unfortunately come up with rather monstrous solutions like eval.call(window, '...'), window.eval.call(window, '...') and even scarier combinations. All of those are, once again, nothing but indirect eval calls.
There's also a very nice paragraph describing why (0, eval)(pString)
is indirect. Please have a look. Unfortunately, I could find any proper reason to justify why eval.call(this, '...')
is indirect. Maybe we will have to satisfy with the statement like eval()
is not a real function().
PS: The eval function is very dangerous and should be used with precaution !!!
But, because I'm kind, I will show you how to make your code work: In order to specify the context of your eval function you can use the call javascript function like this:
this.TestClass.Run.call(this, "this.arrTest2 = [2];");
PS2: Generally, you don't need to use the eval function, you can explain even without giving the whole code behind your desired behavior and people can help you figure out how to make it work.
EDIT: If your desired behavior is to have dynamic arrays/values, you can use a simple object and add your attribute to it dynamically. Let say your object is A: You can use A[varName] to create an object attribute dynamically.
I had a similar problem with eval and ended up using the following IIFE.
Expressions are coming from a backend something like: "Client === 123". No option to change them.
"eval" will not understand it directly. Since in TS member variables are accessed with the "this" keyword. Something like "this.Client" etc.
One possible workaround is to have a function and add required variables inside it then invoke eval.
testEval(expression: HTMLInputElement) {
const result = (() => {
const Client = this.clientNumber;
return eval(expression.value);
})();
this.expressionResult = `expression: [${expression.value}], result: [${result}]`;
}
StackBlitz Demo