I did some crazy stuff in a case like this but you may think it is extreme. In my case I had to store some functions in localStorage and execute them by history state ( when user goes back/forth ). I have created a json object similar to
{obj:'myObject', fn: 'myfn', args: myArgs}
then stored this data base64 encoded. then when I need it back, I simply decoded content and
window.[data.fn].[data.obj].apply(null,data.args)`
did the trick without exposing too much data and not using eval. Eval comes from Evil so I would stay away. =)
UPDATE
So in my case all main core functions are json objects at window namespace similar to ( not actual content but an sample)
Member = {
initialize: function (){
//some process
},
render:function(memberId, selector){
//Some process
},
//...etc }
So when I store each item it, I used something similar to
var data = {obj: 'Member', fn: 'render', args: [1,'#member-block']}
then encoded version will be
localStorage.setItem('data', btoa(JSON.stringify(data)));
dmFyIGRhdGEgPSB7b2JqOiAnTWVtYmVyJywgZm46ICdyZW5kZXInLCBhcmdzOiB7bWVtYmVySWQ6MSwgc2VsZWN0b3I6ICcjbWVtYmVyLWJsb2NrJ319
Then when I need to call back
var data = JSON.parse(atob(localStorage.getItem('data'));
would return my original data object. Since the main functions in my case are in window namespace.
if (typeof window[data.obj]!=='undefined') { // same as window.Member
if (typeof window[data.obj][data.fn]!=='undefined' && typeof window[data.obj][data.fn]!=='function' ) { // make sure fn is defined and is a function
window[data.obj][data.fn].apply(null, data.args);
// we pass same arguments to function call with apply.
// `apply` will give us option to add arguments dynamically without knowing its size.
// it can be null any number of arguments that needed for that function.
}
}