问题
I know that there are other threads on this topic but I am asking again because I am really trying hard to understand eval and how to use it correctly so that it doesn't become evil. By looking at this code, how can I get the console.log(this.arrTest);
to log ['Back to Original']
? I tried many variations and none of them work.
I do not want this solution please: this.TestClass.Run.call(this, "this.arrTest = ['Back to Original'];");
I want a solution inside the class level.
Here is an angular blitz to play with: https://stackblitz.com/edit/angular-mtuvvz?file=src%2Fapp%2Fapp.component.ts
export class AppComponent {
arrTest = ['Original'];
constructor() {
this.TestClass.Run("this.arrTest = ['Back to Original'];");
console.log(this.arrTest);
};
TestClass = {
Run : (pString) => {
this.arrTest = ['Changed']; //So this works
eval(pString); //Why is this not working
eval.call(this, pString); //Why is this not working
eval.call(null, pString); //Why is this not working
(1, eval)(pString); //Why is this not working
(eval)(pString); //Why is this not working
var my_eval = eval; //Why is this not working
my_eval(pString); //Why is this not working
}
};
}
I have read both of these articles but I don't understand a solution from them:
http://2ality.com/2014/01/eval.html
http://blog.klipse.tech/javascript/2016/06/20/js-eval-secrets.html
回答1:
There is no way to make eval
not 'evil' in this case, because it is evil. An appropriate idiomatic solution should be used instead.
eval(pString);
(eval)(pString);
are the ways it's supposed to be workable, they are essentially the same because wrapping eval
with parentheses does nothing. The rest of eval
s are used indirectly, this results in evaluating the code in global scope.
This will work only with ES6 target. It can be seen what the class transpiles to with ES5 target, var _this = this
trick is used to pass this
from enclosing scope to arrow function. this
remains unchanged inside Run
method and is TestClass
object, not class instance. For this reason
this.TestClass.Run("_this.arrTest = ['Back to Original'];");
will work with ES5 but not ES6 TypeScript target.
This is a good example that shows why eval
is considered 'evil'. It results in untyped, unpredictable, unsafe and unoptimized mess that could be avoided by following 'good' coding practices.
It's unclear what are the requirements for TestClass.Run
but usually such scenarios are handled with callbacks:
constructor() {
this.TestClass.Run(() => {
this.arrTest = ['Back to Original'];
});
console.log(this.arrTest);
};
TestClass = {
Run : (cb: () => void) => {
// class instance can be passed to callback as an argument
// or cb.call(this) when needed
cb();
}
};
Depending on what are the reasons to introduce TestClass
member to execute code within the class it belongs to, this still may be considered unsuitable solution.
回答2:
So this solves the problem quite well in my scenario:
export class AppComponent {
arrTest = ['Original'];
constructor() {
this.TestClass.Run("arrTest", "['Back to Original']");
console.log(this.arrTest);
};
TestClass = {
Run : (pKey, pValue) => {
this.arrTest = ['Changed']; //So this works
this[pKey] = pValue;
}
};
}
来源:https://stackoverflow.com/questions/50295983/understanding-eval-reference