7

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

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

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

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

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

谢谢你的帮助。

4

7 回答 7

10

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

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

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

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

http://jsfiddle.net/kceTr/

哦 - 我不确定那是编辑还是我之前错过了 - 但重新:评估。

评估是一个工具。您想在数据库中存储一个函数。如果您必须“评估”将其转换为代码,或者有其他一些神奇的方法可以做到这一点,这真的没有太大区别:如果有人可以更改您数据库中的数据,那么他们可以更改一个函数。

如果你需要存储一个函数,那么 eval 就是你的工具。它本质上并不“坏”,它很糟糕,因为它很容易被滥用。用得好不好,就看你自己了。

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

于 2012-07-28T03:16:34.167 回答
2

更改对象的原型是我的一半想法。

你的图书馆就像

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

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

theObj.__proto__ = library["myObj"];

这样你就可以执行

theObj.function(...);

jsfiddle示例(这很粗糙!)。另外,小心proto,它已被弃用 ( 1 ) ( 2 )

至于序列化函数,您可以使用脚本标记来获取它们,该标记​​指向服务器端的东西,从数据库中获取它们并返回 js 吗?只是在渲染页面时将它们内联(在脚本块中)?或者,如果所有其他方法都失败了, eval 应该可以工作,只要您知道存储在数据库中的函数是干净且安全的。

于 2012-07-28T04:15:36.920 回答
0

你用它做什么就好了。但是,如果我是你,为了可读性和整洁性,我宁愿在外部创建函数并将其分配给你的对象键。

你不需要 eval 这里。而是在您想要访问存储的功能时这样做 -

库.myObj.function()

于 2012-07-28T06:10:53.423 回答
0

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

于 2012-07-28T02:58:14.397 回答
0
  • 您尽最大努力对函数进行参数化,以便最终得到尽可能少的类型。
  • 将它们存储在单独的 JS 文件中的服务器上,然后按名称动态加载所需的文件。
  • 在 JSON 中,只存储包含您需要的函数的文件的名称。而且,当然,您将缓存已加载的文件,以便在服务器上轻松进行。

只是我的两分钱。

于 2016-12-31T22:44:48.847 回答
0

没有正确的方法可以做到这一点,因为它通常不是一个好主意。

但是,如果您想这样做,您可以简单地使用.toJSON方法扩展 Function 的原型。

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

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

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

于 2019-08-11T12:42:29.747 回答
0

您只能真正序列化一个包含require调用的整个文件。如果这样做,您可以创建一个模块、exports 和 module.exports,使用围绕它的函数评估文件并从中提取 module.exports。

它并不完全安全,但为此您需要使用VM2价值审查(我一直在研究)之类的东西,以避免他们调用 eval() 并拥有您的机器或整个网络。

于 2019-01-31T19:36:35.243 回答