通过JSON传递JavaScript函数

Kit*_*Kit 2 javascript json function object

我有一个服务器端Python脚本,它返回一个包含客户端JavaScript参数的JSON字符串.

# Python
import simplejson as json

def server_script()
  params = {'formatting_function': 'foobarfun'}
  return json.dumps(params)
Run Code Online (Sandbox Code Playgroud)

foobarfun应该引用JavaScript函数.这是我的主要客户端脚本

// JavaScript
function client_script() {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, async=true);
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
      options = JSON.parse(xhr.responseText);
      options.formatting_function();
    }
  };
  xhr.send(null);
}

function foobarfun() {
  //do_something_funny_here...
}
Run Code Online (Sandbox Code Playgroud)

当然,options.formatting_function()会抱怨"字符串不可调用"或类似的东西.

在使用Chrome的Inspect Element后,在Resources选项卡下,并导航左侧边栏以进行XHR>查询,我发现client_script解释options如下.foobarfun被视为一个字符串.

// JavaScript
options = {"formatting_function": "foobarfun"}
Run Code Online (Sandbox Code Playgroud)

我本来希望client_script看到options

// JavaScript
options = {"formatting function": foobarfun}
Run Code Online (Sandbox Code Playgroud)

当然,在Python中执行以下操作会让它抱怨它不知道任何事情 foobarfun

# Python
params = {'formatting_function': foobarfun}
Run Code Online (Sandbox Code Playgroud)

问题:
我应该如何从服务器端准备我的JSON字符串,以便客户端脚本可以正确解释它?在这种情况下,我希望foobarfun被解释为一个函数对象,而不是一个字符串.

或者也许这是我应该在客户端做的事情?

T.J*_*der 8

你无法在JSON中做任何事情来获得你想要的结果,因为JSON没有函数的概念,它纯粹是一种数据符号.但是你可以做客户端的事情.

如果你的foobarfun函数是一个全局函数(我建议反对,我们会讨论它),那么你可以像这样调用它:

window[options.formatting_function]();
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为全局函数是window对象的属性,您可以使用点分表示法和文字(window.foobarfun),或使用括号表示法和字符串(window["foobarfun"])来访问属性.当然,在后一种情况下,字符串不必是字符串文字,它可以是属性的字符串 - options.formatting_function例如,您的属性.

但我不建议使用全局函数,该window对象已经非常拥挤.相反,我将所有函数(或在一些边缘情况下尽可能多)保留在主范围函数中,因此我不向全局命名空间添加任何内容:

(function() {
    function foobarfun() {
    }
})();
Run Code Online (Sandbox Code Playgroud)

现在,如果你这样做,你就无法访问foobarfun,window因为这样做的全部目的是避免它被打开window.相反,您可以创建自己的对象并使其成为以下属性:

(function() {
    var myStuff = {};

    myStuff.foobarfun = foobarfun;
    function foobarfun() {
    }

    function client_script() {
      var xhr = new XMLHttpRequest();
      xhr.open("GET", url, async=true);
      xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
          options = JSON.parse(xhr.responseText);
          myStuff[options.formatting_function]();   // <== using it
        }
      };
      xhr.send(null);
    }
})();
Run Code Online (Sandbox Code Playgroud)

通常,而不是这样:

myStuff.foobarfun = foobarfun;
function foobarfun() {
}
Run Code Online (Sandbox Code Playgroud)

你会看到人们写道:

myStuff.foobarfun = function() {
};
Run Code Online (Sandbox Code Playgroud)

我也不建议这样做,因为那时你的函数是匿名的(该属性myStuff就是指函数有一个名字,但函数却没有).给你的函数名称是一件好事,它可以帮助你的工具帮助你(显示调用堆栈中的名称,错误消息等).

您可能还会看到:

myStuff.foobarfun = function foobarfun() {
};
Run Code Online (Sandbox Code Playgroud)

应该是有效的,这是正确的JavaScript.但不幸的是,各种JavaScript实现都有各种各样的错误(称为命名函数表达式),尤其是IE9之前的Internet Explorer,它将在两个不同的时间创建两个完全不同的函数.

所有这些都说,在客户端和服务器之间传递函数名称通常表明你想退后一步再看一下设计.数据应该驱动逻辑,但不是以这种字面方式.尽管如此,这样做肯定是有效的用例,你可能在你的情况下有一个.