为什么函数不可序列化?

Why is a function not serializable?

背景

Meteor.call() 的 Meteor 文档中,它显示:

If you include a callback function as the last argument (which can't be an argument to the method, since functions aren't serializable)...

我之前有 运行 类似于 Meteor.call('name', function() {console.log('abc');}, function() {}) 的内容,其中 function() {console.log('abc');} 作为 参数传入 ,空 function() {} 用作异步回调的存根。 而且有效。

那句话告诉我我不应该将 任何 函数作为参数传递给函数,或者只适用于回调函数。

问题

在这两种情况下,为什么该函数不可序列化?我的浅薄理解只是,可序列化对象是一个可以将其转换为位序列(10 的对象),并且由于 everything 数字是位序列,我不明白为什么函数不可序列化。

我找到了一些explanations,但它们都与Java有关,对于还不知道连载意义的人来说,帮助不大。

为什么函数不可序列化?(它与 Meteor.call() 有什么关系?)

我相信这归结为序列化的格式。一般来说,我遇到的几乎每个例子都使用 JSON 来序列化 Javascript 对象,然后简单地把 JSON 不支持 function 数据类型。

如果您查看 json.org,您可以看到支持的数据类型。您可以在取自同一站点的下图中看到支持的不同值:

最接近函数的方法是将其表示为字符串,但在反序列化过程中,没有任何信息可告知您如何 re-hydrate 返回 Javascript 函数。

在大多数情况下,可序列化意味着您可以将某些内容转换为与语言无关的表示形式,并在其他地方重建原始状态。例如。数组 [0,1,2] 可以序列化为 JSON "[0,1,2]" 并在其他地方反序列化。

In either case, why is that function not serializable?

一个函数对象(在 JS 中)由两部分组成:它的主体(代码)和它定义的环境。每个函数都是一个闭包。获取函数的源代码很容易,但你无法获取其环境的状态。

示例:

var foo = 42;
function bar() {
    console.log(foo);
}

thirdService(bar);

thirdService 不知道函数定义的环境。它所能做的就是获取函数体的字符串表示,但它不知道 [=14 的值=].

以下面的对象为例

var aFancyValue = 123;
var obj = {
   propName: "A value"
   funcName: function(){
      // you do something fancy with aFancyName variable
   }
}

现在,当您尝试序列化 obj 时,如果函数是可序列化的,那么 aFancyValue 应该以某种方式存在,否则函数将无法工作。

属性等其他内容都是文字,它们不依赖于任何其他内容。它们本身是完整的,但函数 可能 不是那样,因为它们可能取决于数据,在序列化时可能无法访问这些数据。

简而言之,函数的环境,上下文是未知的,这就是它们无法序列化的原因。

Meteor 文档中该语句的意思是 API (Meteor.call) 可以告诉您将回调作为最后一个参数传递,因为它知道参数是一个函数不能 是要传递给服务器的参数之一,因为这些参数必须可序列化为 JSON。

所以:当你使用Meteor.call()调用方法时,第一个参数是要调用的方法的名称。然后传入零个或多个参数以传递给该方法,并且每个参数都必须表示为 JSON。最后,如果你想要一个异步回调,你将它作为最后一个参数传递。

将其与 Meteor.apply() 进行对比,后者做同样的事情,但采用 三个 参数:方法名称、参数值数组和(可选)回调.因为所有的方法参数都在数组中,所以不需要做任何"sniffing"来决定是否有回调参数。