سؤال

Without starting a war on whether or not I should use eval(), I am trying to make a constructive discussion on how I can avoid (if possible) using eval() in the following scenario?

I am loading remote html templates into an SPA, to save calls I am loading json that looks like the following:

{
  "template":"",
  "contentScript":"",
  "viewModel":""
}

Where template is html, contentScript is combined script files and viewModel is a single script file.

ContentScript

When the json request is received (either from server or localdb) I create an anonymous function (so all variables are locally scoped to this template script) for the contentScript that looks like:

(function(event, view) 
 {
   // js content here
 });

where the event object is a shared object that the contentScript and viewmodel communicate over using a pub/sub pattern and the view object is the DOM element that is the template.

the only way I can see to get this pattern working is by using the following code:

var script = 'function(event, view) {' + json.contentScript + '});';
views[name].script = eval(script);

where views[name] is a collection of all the templates in the SPA so I can get them and rebind them easily given a name.

each time the view is rendered I can then simply call (to execute the script):

views[name].script.apply(window, [ views[name].eventObj, views[name].view ]);

ViewModel

The view model is a slightly different case as I need the properties on that object to be visible for binding, so it cannot be an anonymous function. To achieve the desired result I am creating the viewModel object as an object literal like:

var viewmodel = 
{
   init: function(event, view)
   {
      this.event = event;
      this.view = view;
   },

   ... other stuff
}

When the viewModel json is received I run a regex over it to ensure the init signature matches what is expected and then eval() it like:

eval(json.viewModel);
views[name].model = observable(viewmodel); // viewmodel var is available from eval'ing the contentScript

views[name].model.init(views[name].eventObj, views[name].view);

new Function

I have also tried using Function('script as string') which is also frowned upon. However this does not support both cases, as it creates an anonymous function around my anonymous function which requires an extra step of inspecting arguments to pass the variable down to my anonymous function. More importantly, it also hides the properties of the object literal preventing data binding from working.

Conclusion

I cannot see any issues with what I am doing here but am curious as to how this could be achieved using other means. I have spent considerable time trying different ideas and none allow both scenarios to work effectively.

هل كانت مفيدة؟

المحلول

How can I avoid using eval() in this scenario?

I cannot see any issues with what I am doing here but am curious as to how this could be achieved using other means. I have spent considerable time trying different ideas and none allow both scenarios to work effectively.

I believe the question deserves an answer.

As you want to evaluate your string of Javascript code in the local scope then I don't believe that using eval can be avoided in your case. One word of warning.

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, third party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways of which the similar Function is not susceptible.

Some interesting reading can be found at Perfection Kills by kangax

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top