在javascript中“序列化”函数以供以后使用的正确方法是什么

时间:2012-07-28 02:53:41

标签: javascript json function object

我有一个对象的“库”,我想从数据库中动态加载。每个对象都有自己的特殊函数,这些函数在特定时间根据对象类型调用。理想情况下,我希望能够做到这一点,尽管有人指出这不起作用:

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

字符串"myObj"在我的程序中传递了很多,但我只需要一次访问对象的某些值,在某些情况下,需要运行一个特定的函数。问题在于,我正在研究数百个,最终成千上万个可能存在不同功能的潜在对象。

存储要像这样调用的函数的“正确”方法是什么。我知道在执行期间调用eval会非常不安全,从而实现xss攻击等等。我真的想避免大量的switch语句或额外函数的膨胀加载。我也希望解决方案尽可能简洁。

这可能不是第一次出现。 ; /

感谢您的帮助。

7 个答案:

答案 0 :(得分:8)

在将其作为字符串加载后,只需使用eval重新创建该函数。因此,如果您从JSON反序列化对象myObj,并且您有一个属性:

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

你可以很容易地把它变成一个真正的功能:

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

http://jsfiddle.net/kceTr/

哦 - 我不确定这是否是编辑或我之前错过了 - 但重新:eval。

Eval是一种工具。您希望将函数存储在数据库中。如果你必须“eval”把它变成代码,或者还有其他一些神奇的方法可以做到这一点,那真的没什么区别:如果有人可以改变数据库中的数据,那么他们就可以改变一个功能。

如果您需要存储功能,那么eval就是您的工具。它本质上并不“坏”,它很糟糕,因为它容易被滥用。是否使用它取决于你。

记住客户端上运行的任何内容仍然只在客户端上运行。没有任何恶意的人可以使用eval,他们无法轻松地使用Chrome调试器。任何人都可以随时在客户端上运行他们想要的任何代码,由服务器来决定如何处理它收到的内容。首先,客户端没有任何安全措施......

答案 1 :(得分:1)

改变对象的原型是我认为的一半。

你的图书馆就像

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

你有一个对象(让我们称之为theObj),你知道它是myObj(由于字符串可能是?属性?)

theObj.__proto__ = library["myObj"];

这样你可以执行

theObj.function(...);

jsfiddle示例(它是粗略!)。此外,请注意 proto ,不推荐使用(1)(2

至于序列化这些函数,你是否可以使用一个脚本标记来指向某些服务器端,这些服务器从数据库中剔除它们并返回js?只需在渲染页面时将它们包含在内(在脚本块中)?或者,如果所有其他方法都失败了,只要您知道存储在数据库中的函数是干净且安全的,eval应该可以正常工作。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

你正在做什么就好了。但是,如果我是你,为了可读性和整洁性,我宁愿在外面创建函数,只需将它分配给你的对象密钥。

这里你不需要eval。相反,只要您想要访问存储的函数,就这样做 -

library.myObj.function()

答案 4 :(得分:0)

  • 您尽力参与功能参数设置,以便最终完成 尽可能少的类型。
  • 将它们存储在服务器中的各个JS文件中,然后按名称动态加载所需的文件。
  • 在JSON中,仅存储包含所需功能的文件的名称。当然,您将缓存已加载的文件,以便在服务器上轻松实现。

只是我的两分钱。

答案 5 :(得分:0)

您只能真正序列化带有require调用的整个文件。如果这样做,则可以创建一个模块,exports和module.exports,使用围绕它的函数对文件进行评估,然后将module.exports导出其中。

这并不完全安全,但是为此,您需要使用VM2value-censorship之类的东西(我一直在努力),以避免它们调用eval()并拥有您的计算机或整个网络。

答案 6 :(得分:0)

没有正确的方法,因为通常这不是一个好主意。

但是,无论如何,只要使用 upload(event){ const id = Math.random().toString(36).substring(2); this.ref = this.afStorage.ref(id); this.task = this.ref.put(event.target.files[0]); this.downloadURL = concat( this.task.snapshotChanges().pipe(filter(() => false)), defer(() => this.ref.getDownloadURL()), ); } 方法扩展Function的原型即可。

.toJSON

然后您可以简单地使用JSON.stringify,函数将被序列化为字符串。

在大多数情况下,这通常不是一个好主意。在极少数情况下,您想这样做,即使那样,也可能有更好的方法。