简体   繁体   中英

What is the correct way to “serialize” functions in javascript for later use

I have a "library" of objects that I want to load on the fly from a database. Each object comes with its own special functions that are called at specific times depending on the objects type. Ideally I'd like to be able to do this, although its been pointed out that this doesn't work:

library = {
  "myObj" : {"name" : "myObj", "type" : "myType", "function" : function () { } } //, etc
}

The string "myObj" is passed around my program quite a bit, but I only have to access certain values of the object at a time, and in some circumstances there's a specific function that needs to be run. The problem is that I'm looking at hundreds, and eventually thousands, of potential objects that could exist with varying functions.

What is the "right" way to store a function to be called like this. I know that calling eval can be very unsafe during execution, enabling xss attacks and whatnot. I really want to avoid a massive switch statement or the bloated loading of additional functions. I'd also like the solution to be as concise as possible.

This can't be the first time this has come up. ;/

Thanks for your help.

Just use eval to recreate the function after loading it as a string. So if you deserialize an object myObj from JSON, and you have a property:

myObj = {
    ....
    function: "function() { ... }"
}

you can very easily turn it to a real function:

eval("myObj.func = " + myObj.func);

http://jsfiddle.net/kceTr/

Oh - I am not sure if that was an edit or I missed it before - but re: eval.

Eval is a tool. You want to store a function in a database. It really doesn't make much difference if you have to "eval" to turn it into code, or there was some other magic way to do it: if someone can change the data in your DB, then they can change a function.

If you need to store a function, then eval is your tool. It's not "bad" by nature, it's bad because it's easy to misuse. Whether you use it well or not is up to you.

Remember anything running on the client is still just running on the client. There's nothing a malicious person could do with eval, that they couldn't do with the Chrome debugger a lot more easily. Anyone can always run any code they want on the client, it's up to your server to decide how to handle what it receives. There's nothing safe on the client in the first place...

Changing the prototype of the object is a half thought I have.

You've got your library like

library = {
  "myObj" : {"name" : "myObj", "type" : "myType", "function" : function () { } } //, etc
}

You've got an object (let's call it theObj ) that you know is a myObj (due to a string maybe? property?)

theObj.__proto__ = library["myObj"];

That way you can execute

theObj.function(...);

jsfiddle example (it's rough !). Also, be careful with proto , it's deprecated ( 1 ) ( 2 )

As to serializing the functions, can you get them in using a script tag that points to something serverside that slurps them from the db and returns the js? Just include them inline as you render the page (in a script block)? Or, if all else fails, eval should work, as long as you know that the functions you've got stored in the database are clean and safe.

更好的方法可能是在“睡眠”时序列化对象的属性,并通过使用定义的适当方法将其属性重新附加到对象的新实例来“唤醒”对象。

what you are doing with it is just fine. However, if i were you, for readability and tidyness, i would rather have the function created outside and simply have it assigned to your object key.

You don't need eval here. Instead do it this way whenever you want access to the stored function -

library.myObj.function()

  • You do your best in parameterising your functions, so that you end up with as little typologies as possible.
  • Store them on the server in individual JS files, then load the needed file dynamically, by name.
  • In the JSON, only store the name of the file that contains the function that you need. And, of course, you will be caching already loaded files, to go easy on the server.

Just my two cents.

You can only really serialise a whole file with require calls in it. If you do that, you can create a module, exports and module.exports, eval the file with a function surrounding it and snag the module.exports out of it.

It's not exactly secure, but for that you need to use something like VM2 and value-censorship (which I've been working on) to avoid them calling eval() and owning your machine or the entire network.

There is no right way to do this, because its not generally a good idea.

HOWEVER, if you want to do it anyways you can simply extend the prototype of Function with a .toJSON method.

Function.prototype.toJSON = function(){ return this.toString(); }

Then you can simply use JSON.stringify and functions will be serialized as strings.

Its generally a not good idea in most cases. There are very few circumstances where you want to do this and even then, there is probably a better way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM