Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular/Typescript Eval and this

So I am having a problem understanding how eval works with this in typescript/angular. Could someone please help me get the eval to work here? This is just a demo program so just ignore the fact that the logic doesn't make sense. I would just like to have eval update a dynamic array with a dynamic value.

https://stackblitz.com/edit/angular-pfyt7q?file=src%2Fapp%2Fapp.component.ts

export class AppComponent  {
  arrTest1 = [];
  arrTest2 = [];
  arrTest3 = [];

  constructor() {
    this.TestClass.Run("this.arrTest1 = [1];");
    this.TestClass.Run("this.arrTest2 = [2];");
    this.TestClass.Run("this.arrTest3 = [3];");
    console.log(this.arrTest1);   //Logs: [] (I want: [1])
    console.log(this.arrTest2);   //Logs: [] (I want: [2])
    console.log(this.arrTest3);   //Logs: [] (I want: [3])
  };

  TestClass = {
    Run : (pString) => {
      (0, eval)(pString);
      eval(pString);
    }
  };

}
like image 217
Frank Avatar asked May 11 '18 11:05

Frank


People also ask

Can we use eval in angular?

We can use the $eval function in Angular to evaluate an expression at runtime. It is beneficial when you want to dynamically create a DOM element and add it to the DOM or when you need to do something with an object that doesn't have any other way of being accessed.

What can I use instead of eval?

An alternative to eval is Function() . Just like eval() , Function() takes some expression as a string for execution, except, rather than outputting the result directly, it returns an anonymous function to you that you can call. `Function() is a faster and more secure alternative to eval().

What is $$ eval?

page.$$eval(selector, pageFunction[, ...args])This method runs Array. from(document. querySelectorAll(selector)) within the page and passes it as the first argument to pageFunction . If pageFunction returns a Promise, then page. $$eval would wait for the promise to resolve and return its value.

What does eval do in typescript?

The eval() function evaluates JavaScript code represented as a string and returns its completion value. The source is parsed as a script.


2 Answers

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().

like image 129
Ashish Ranjan Avatar answered Sep 20 '22 11:09

Ashish Ranjan


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.

like image 25
Mehdi Benmoha Avatar answered Sep 18 '22 11:09

Mehdi Benmoha